aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/dirvish-config.el2
-rw-r--r--modules/dwim-shell-config.el20
-rw-r--r--tests/test-dwim-shell-config-command-fixes.el33
-rw-r--r--todo.org10
4 files changed, 59 insertions, 6 deletions
diff --git a/modules/dirvish-config.el b/modules/dirvish-config.el
index 29ba2eba..79d6ff41 100644
--- a/modules/dirvish-config.el
+++ b/modules/dirvish-config.el
@@ -27,7 +27,7 @@
;; - p: Copy absolute file path
;; - P: Print the file at point via CUPS
;; - S: Study — start an org-drill session on the .org file at point
-;; - M-S-d (Meta-Shift-d): DWIM shell commands menu
+;; - M-D (Meta-Shift-d): DWIM shell commands menu
;; - TAB: Toggle subtree expansion
;; - F11: Toggle sidebar view
diff --git a/modules/dwim-shell-config.el b/modules/dwim-shell-config.el
index 655c8d85..ad17ea91 100644
--- a/modules/dwim-shell-config.el
+++ b/modules/dwim-shell-config.el
@@ -198,6 +198,18 @@ file list."
(replace-regexp-in-string "'" "'\\\\''" (expand-file-name f))))
files "\n"))
+(defun cj/dwim-shell--zip-single-file-command ()
+ "Return the zip command template for a single marked file.
+The archive is named =<fne>.zip=, not a reconstruction of the input filename
+\(which produced invalid archives, and a `foo.' name for a directory)."
+ "zip -r '<<fne>>.zip' '<<f>>'")
+
+(defun cj/dwim-shell--dated-backup-command ()
+ "Return the cp command template for a timestamped backup of marked file(s).
+The timestamp is interpolated here with `format-time-string' so it can't sit
+dead inside the shell's single quotes the way a literal =$(date ...)= did."
+ (format "cp -p '<<f>>' '<<f>>.%s.bak'" (format-time-string "%Y%m%d_%H%M%S")))
+
;; ----------------------------- Dwim Shell Command ----------------------------
(use-package dwim-shell-command
@@ -337,7 +349,7 @@ Otherwise, unzip it to an appropriately named subdirectory "
(interactive)
(dwim-shell-command-on-marked-files
"Zip" (if (eq 1 (seq-length (dwim-shell-command--files)))
- "zip -r '<<fne>>.<<e>>' '<<f>>'"
+ (cj/dwim-shell--zip-single-file-command)
"zip -r '<<archive.zip(u)>>' '<<*>>'")
:utils "zip"))
@@ -547,8 +559,8 @@ clipboard contents cannot inject shell commands."
(interactive)
(dwim-shell-command-on-marked-files
"Backup with date"
- "cp -p '<<f>>' '<<f>>.$(date +%Y%m%d_%H%M%S).bak'"
- :utils '("cp" "date")))
+ (cj/dwim-shell--dated-backup-command)
+ :utils '("cp")))
(defun cj/dwim-shell-commands-optimize-image-for-web ()
"Optimize image(s) for web (reduce file size)."
@@ -930,7 +942,7 @@ gpg: decryption failed: No pinentry"
;; Bind menu to keymaps after function is defined
(with-eval-after-load 'dired
- (keymap-set dired-mode-map "M-S-d" #'dwim-shell-commands-menu)) ;; was M-D, overrides kill-word
+ (keymap-set dired-mode-map "M-D" #'dwim-shell-commands-menu)) ;; Meta-Shift-d; matches the dirvish binding below
(with-eval-after-load 'dirvish
(keymap-set dirvish-mode-map "M-D" #'dwim-shell-commands-menu)))
diff --git a/tests/test-dwim-shell-config-command-fixes.el b/tests/test-dwim-shell-config-command-fixes.el
new file mode 100644
index 00000000..2f49a868
--- /dev/null
+++ b/tests/test-dwim-shell-config-command-fixes.el
@@ -0,0 +1,33 @@
+;;; test-dwim-shell-config-command-fixes.el --- zip/backup command builders -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Two audit fixes, extracted into top-level command-string builders so they're
+;; testable without loading the dwim-shell-command package (the command defuns
+;; that call them live inside its use-package :config, which the batch test
+;; harness doesn't instantiate):
+;; - cj/dwim-shell--zip-single-file-command names the archive <fne>.zip
+;; - cj/dwim-shell--dated-backup-command carries a real timestamp, not "$(date)"
+;; The third fix (dired menu key M-S-d -> M-D) is a keybinding inside the same
+;; :config block; it's verified in the live daemon, not here.
+
+;;; Code:
+
+(require 'ert)
+(require 'dwim-shell-config)
+
+(ert-deftest test-dwim-zip-single-file-command-names-archive-dot-zip ()
+ "Normal: the single-file zip template names the archive <fne>.zip, with no
+leftover <<e>> that would rebuild the input filename."
+ (let ((cmd (cj/dwim-shell--zip-single-file-command)))
+ (should (string-match-p "'<<fne>>\\.zip'" cmd))
+ (should-not (string-match-p "<<e>>" cmd))))
+
+(ert-deftest test-dwim-dated-backup-command-carries-real-timestamp ()
+ "Normal: the dated-backup template interpolates a real YYYYMMDD_HHMMSS stamp,
+so the substitution can't sit dead inside single quotes."
+ (let ((cmd (cj/dwim-shell--dated-backup-command)))
+ (should (string-match-p "\\.[0-9]\\{8\\}_[0-9]\\{6\\}\\.bak'" cmd))
+ (should-not (string-match-p "\\$(date" cmd))))
+
+(provide 'test-dwim-shell-config-command-fixes)
+;;; test-dwim-shell-config-command-fixes.el ends here
diff --git a/todo.org b/todo.org
index 6cd4cadb..097c7d4e 100644
--- a/todo.org
+++ b/todo.org
@@ -903,11 +903,13 @@ From the 2026-06 config audit, =modules/slack-config.el=:
** TODO [#B] dirvish M (mark all files) marks every other file :bug:quick:solo:
=modules/dirvish-config.el:218= — =dired-mark= advances point to the next line itself; the loop's extra =forward-line 1= then skips it, so consecutive files are marked alternately. Live mis-marking on a key that feeds batch operations (delete/copy on marked files) — data-loss adjacent. Drop the manual forward-line when a mark was made (or =dired-unmark-all-marks= + mark dirs + =dired-toggle-marks=). The trivial line-predicate helper is tested; the loop isn't — add the marked-count test. From the 2026-06 config audit.
-** TODO [#B] dwim-shell: zip overwrites its own name, backup timestamp never expands, dired menu key dead :bug:quick:solo:
+** DONE [#B] dwim-shell: zip overwrites its own name, backup timestamp never expands, dired menu key dead :bug:quick:solo:
+CLOSED: [2026-06-13 Sat]
From the 2026-06 config audit, =modules/dwim-shell-config.el=:
- =:338= — single-file zip is =zip -r '<<fne>>.<<e>>' '<<f>>'= — reconstructs the input filename as the archive ("Zip file structure invalid"; directories produce =foo.=). Should be ='<<fne>>.zip'= like the tar-gzip sibling.
- =:549= — backup destination single-quotes =$(date ...)= so the substitution is literal: =foo.txt.$(date +%Y%m%d_%H%M%S).bak=. Move it outside the quotes or format-time-string in Elisp.
- =:932= — dired-mode binding "M-S-d" is unreachable (Meta+Shift+d generates M-D); the dirvish binding two lines down is correctly "M-D". Fix + the stale commentary at dirvish-config.el:30.
+Fixed 2026-06-13: zip single-file template now ='<<fne>>.zip'=; backup uses =format-time-string= in Elisp (real =YYYYMMDD_HHMMSS= stamp, dropped the now-unneeded =date= util); dired key M-S-d→M-D + dirvish-config.el:30 doc corrected. Both command strings extracted into top-level builders (=cj/dwim-shell--zip-single-file-command=, =cj/dwim-shell--dated-backup-command=) so they're unit-testable without the dwim-shell-command package — the command defuns live in its use-package :config, which the batch harness doesn't load. 2 builder tests green in make; live daemon confirms all three (backup stamp, .zip, dired M-D). Real backup/zip run + the dired keypress are a VERIFY.
** TODO [#B] Go: format key void-functions, go-mode :config never runs :bug:quick:solo:
=modules/prog-go.el:99,113-118= — .go maps to go-ts-mode so the go-mode package never loads, and =gofmt= isn't autoloaded in go-mode 1.6.0 — C-; f signals void-function, and the :config (exec-path += ~/go/bin, =gofmt-command "goimports"=) never executes. Wrapper that requires go-mode first (or autoload gofmt), move the setup to top level. From the 2026-06 config audit.
@@ -4342,6 +4344,12 @@ From the 2026-06-11 messenger-unification brainstorm. Google Voice has no offici
** TODO Manual testing and validation
Exercised once the phases above land.
+*** VERIFY dwim-shell zip/backup/menu-key behave
+What we're verifying: single-file zip makes a valid <name>.zip, the dated backup gets a real timestamp, and the dwim-shell menu is reachable on M-D in plain dired. Fixed in modules/dwim-shell-config.el, reloaded into the daemon.
+- In dired, mark a single file, run the dwim-shell menu (M-D), pick Zip
+- Mark a file, run the menu, pick "Backup with date"
+- Open a plain dired buffer (not dirvish) and press M-D
+Expected: zip produces foo.zip (a valid archive, openable); backup produces foo.ext.YYYYMMDD_HHMMSS.bak with a real date; M-D opens the dwim-shell command menu in plain dired (before the fix it did nothing there).
*** VERIFY markdown live preview renders in the browser
What we're verifying: F2 in a markdown buffer runs the custom cj/markdown-preview (not markdown-mode's own command) and the impatient-mode strapdown preview actually renders. Fixed in modules/markdown-config.el, reloaded into the daemon.
- Open a .md file with some markdown content