>From 2475254565c798725d724ee89e5d699342b6c818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= Date: Wed, 3 Jul 2019 21:17:57 +0200 Subject: [PATCH 3/5] Add '^' markers below non-isolated chars in dired prompt * lisp/dired-aux.el (dired--mark-positions): New function. (dired--no-subst-prompt): Use it to show chars without overly relying on highlighting. (dired-do-shell-command): When the echo area is wide enough to display the command without wrapping it, add the markers. * test/lisp/dired-aux-tests.el (dired-test-highlight-metachar): Add assertion for '^' marker positions. (Bug#35564) --- lisp/dired-aux.el | 43 +++++++++++++++++++++-------- test/lisp/dired-aux-tests.el | 53 ++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 6766c620f6..038e1dbbed 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -102,18 +102,35 @@ dired--need-confirm-positions (setq start (match-end 0))) confirm-positions)) -(defun dired--no-subst-prompt (char-positions command) +(defun dired--mark-positions (positions) + (let ((markers (make-string + (1+ (apply #'max positions)) + ?\s))) + (dolist (pos positions) + (setf (aref markers pos) ?^)) + markers)) + +(defun dired--no-subst-prompt (char-positions command add-markers) (cl-callf substring-no-properties command) (dolist (pos char-positions) (add-face-text-property pos (1+ pos) 'warning nil command)) - (concat command "\n" - (format-message - (ngettext "Send %d occurrence of `%s' as-is to shell?" - "Send %d occurrences of `%s' as-is to shell?" - (length char-positions)) - (length char-positions) - (propertize (string (aref command (car char-positions))) - 'face 'warning)))) + ;; `y-or-n-p' adds some text to the beginning of the prompt when the + ;; user fails to answer 'y' or 'n'. The highlighted command thus + ;; cannot be put on the first line of the prompt, since the added + ;; text will shove the command to the right, and the '^' markers + ;; will become misaligned. + (apply #'concat + `("Confirm:\n" + ,command "\n" + ,@(when add-markers + (list (dired--mark-positions char-positions) "\n")) + ,(format-message + (ngettext "Send %d occurrence of `%s' as-is to shell?" + "Send %d occurrences of `%s' as-is to shell?" + (length char-positions)) + (length char-positions) + (propertize (string (aref command (car char-positions))) + 'face 'warning))))) ;;;###autoload (defun dired-diff (file &optional switches) @@ -796,15 +813,19 @@ dired-do-shell-command (let* ((on-each (not (dired--star-or-qmark-p command "*" 'keep))) (no-subst (not (dired--star-or-qmark-p command "?" 'keep))) (confirmations nil) + (short-enough (< (length command) + (window-width (minibuffer-window)))) ;; Get confirmation for wildcards that may have been meant ;; to control substitution of a file name or the file name list. (ok (cond ((not (or on-each no-subst)) (error "You can not combine `*' and `?' substitution marks")) ((setq confirmations (dired--need-confirm-positions command "*")) - (y-or-n-p (dired--no-subst-prompt confirmations command))) + (y-or-n-p (dired--no-subst-prompt confirmations command + short-enough))) ((setq confirmations (dired--need-confirm-positions command "?")) - (y-or-n-p (dired--no-subst-prompt confirmations command))) + (y-or-n-p (dired--no-subst-prompt confirmations command + short-enough))) (t)))) (cond ((not ok) (message "Command canceled")) (t diff --git a/test/lisp/dired-aux-tests.el b/test/lisp/dired-aux-tests.el index ff18edddb6..174c27052e 100644 --- a/test/lisp/dired-aux-tests.el +++ b/test/lisp/dired-aux-tests.el @@ -115,30 +115,49 @@ dired-test-bug30624 (kill-buffer buf))))) (ert-deftest dired-test-highlight-metachar () - "Check that non-isolated meta-characters are highlighted" + "Check that non-isolated meta-characters are highlighted." (let* ((command "sed -r -e 's/oo?/a/' -e 's/oo?/a/' ? `?`") + (markers " ^ ^") (prompt (dired--no-subst-prompt (dired--need-confirm-positions command "?") - command)) - (result (and (string-match (regexp-quote command) prompt) - (match-string 0 prompt)))) - (should-not (text-property-not-all 1 14 'face nil result)) - (should (equal 'warning (get-text-property 15 'face result))) - (should-not (text-property-not-all 16 28 'face nil result)) - (should (equal 'warning (get-text-property 29 'face result))) - (should-not (text-property-not-all 30 39 'face nil result))) + command + t)) + (lines (split-string prompt "\n")) + (highlit-command (nth 1 lines))) + (should (= (length lines) 4)) + (should (string-match (regexp-quote command) highlit-command)) + (should (string-match (regexp-quote markers) (nth 2 lines))) + (should-not (text-property-not-all 1 14 'face nil highlit-command)) + (should (equal 'warning (get-text-property 15 'face highlit-command))) + (should-not (text-property-not-all 16 28 'face nil highlit-command)) + (should (equal 'warning (get-text-property 29 'face highlit-command))) + (should-not (text-property-not-all 30 39 'face nil highlit-command))) ;; Note that `?` is considered isolated, but `*` is not. (let* ((command "sed -e 's/o*/a/' -e 's/o`*` /a/'") + (markers " ^ ^") (prompt (dired--no-subst-prompt (dired--need-confirm-positions command "*") - command)) - (result (and (string-match (regexp-quote command) prompt) - (match-string 0 prompt)))) - (should-not (text-property-not-all 1 10 'face nil result)) - (should (equal 'warning (get-text-property 11 'face result))) - (should-not (text-property-not-all 12 23 'face nil result)) - (should (equal 'warning (get-text-property 25 'face result))) - (should-not (text-property-not-all 26 32 'face nil result)))) + command + t)) + (lines (split-string prompt "\n")) + (highlit-command (nth 1 lines))) + (should (= (length lines) 4)) + (should (string-match (regexp-quote command) highlit-command)) + (should (string-match (regexp-quote markers) (nth 2 lines))) + (should-not (text-property-not-all 1 10 'face nil highlit-command)) + (should (equal 'warning (get-text-property 11 'face highlit-command))) + (should-not (text-property-not-all 12 23 'face nil highlit-command)) + (should (equal 'warning (get-text-property 25 'face highlit-command))) + (should-not (text-property-not-all 26 32 'face nil highlit-command))) + (let* ((command "sed 's/\\?/!/'") + (prompt (dired--no-subst-prompt + (dired--need-confirm-positions command "?") + command + nil)) + (lines (split-string prompt "\n")) + (highlit-command (nth 1 lines))) + (should (= (length lines) 3)) + (should (string-match (regexp-quote command) highlit-command)))) (provide 'dired-aux-tests) ;; dired-aux-tests.el ends here -- 2.24.0