emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master a8b71b3 1/2: Extend dired-do-shell-command substitu


From: Tino Calancha
Subject: [Emacs-diffs] master a8b71b3 1/2: Extend dired-do-shell-command substitutions
Date: Sun, 2 Jul 2017 09:12:11 -0400 (EDT)

branch: master
commit a8b71b3dc53883a2dcb3339bf4c7e1232c42d276
Author: Tino Calancha <address@hidden>
Commit: Tino Calancha <address@hidden>

    Extend dired-do-shell-command substitutions
    
    Substitute "`?`" inside command with the current file name.
    See details in:
    https://lists.gnu.org/archive/html/emacs-devel/2017-06/msg00618.html
    * lisp/dired-aux.el (dired-quark-subst-regexp, dired-star-subst-regexp):
    Mark as obsolete.
    (dired-isolated-string-re): New defun.
    (dired--star-or-qmark-p): New predicate.
    (dired-do-shell-command): Use dired--star-or-qmark-p.  Substitute "`?`"
    with the current file name.
    * doc/emacs/dired.texi (Shell Commands in Dired): Update manual.
    ; * etc/NEWS: Mention it.
---
 doc/emacs/dired.texi | 26 ++++++++++++++++----------
 etc/NEWS             |  4 ++++
 lisp/dired-aux.el    | 43 ++++++++++++++++++++++++++++++++++---------
 3 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 22b0fcd..28cb51d 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -875,27 +875,33 @@ treat it specially.
 
 @item
 Otherwise, if the command string contains @samp{?} surrounded by
-whitespace, Emacs runs the shell command once @emph{for each file},
-substituting the current file name for @samp{?} each time.  You can
-use @samp{?} more than once in the command; the same file name
-replaces each occurrence.
+whitespace or @samp{`?`}, Emacs runs the shell command once
address@hidden each file}, substituting the current file name for @samp{?}
+and @samp{`?`} each time.  You can use both @samp{?} or @samp{`?`} more
+than once in the command; the same file name replaces each occurrence.
+If you mix them with @samp{*} the command signals an error.
 
 @item
-If the command string contains neither @samp{*} nor @samp{?}, Emacs
-runs the shell command once for each file, adding the file name at the
+If the command string contains neither @samp{*} nor @samp{?} nor @samp{`?`},
+Emacs runs the shell command once for each file, adding the file name at the
 end.  For example, @kbd{! uudecode @key{RET}} runs @code{uudecode} on
 each file.
 @end itemize
 
-  To iterate over the file names in a more complicated fashion, use an
-explicit shell loop.  For example, here is how to uuencode each file,
-making the output file name by appending @samp{.uu} to the input file
-name:
+  To iterate over the file names in a more complicated fashion, you might
+prefer to use an explicit shell loop.  For example, here is how to uuencode
+each file, making the output file name by appending @samp{.uu} to the input
+file name:
 
 @example
 for file in * ; do uuencode "$file" "$file" >"$file".uu; done
 @end example
 
+The same example with @samp{`?`} notation:
address@hidden
+uuencode ? ? > `?`.uu
address@hidden example
+
   The @kbd{!} and @kbd{&} commands do not attempt to update the Dired
 buffer to show new or modified files, because they don't know what
 files will be changed.  Use the @kbd{g} command to update the Dired
diff --git a/etc/NEWS b/etc/NEWS
index 0ba48f3..b9a492c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -483,6 +483,10 @@ properties as intact as possible.
 
 * Changes in Specialized Modes and Packages in Emacs 26.1
 
+** Dired
+You can now use '`?`' in 'dired-do-shell-command'; as ' ? ', it gets replaced
+by the current file name.
+
 *** html2text is now marked obsolete.
 
 *** smerge-refine-regions can refine regions in separate buffers
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 121bebe..a57e5db 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -51,6 +51,33 @@ into this list; they also should call `dired-log' to log the 
errors.")
 
 (defconst dired-star-subst-regexp "\\(^\\|[ \t]\\)\\*\\([ \t]\\|$\\)")
 (defconst dired-quark-subst-regexp "\\(^\\|[ \t]\\)\\?\\([ \t]\\|$\\)")
+(make-obsolete-variable 'dired-star-subst-regexp nil "26.1")
+(make-obsolete-variable 'dired-quark-subst-regexp nil "26.1")
+
+(defun dired-isolated-string-re (string)
+  "Return a regexp to match STRING isolated.
+Isolated means that STRING is surrounded by spaces or at the beginning/end
+of a string followed/prefixed with an space.
+The regexp capture the preceding blank, STRING and the following blank as
+the groups 1, 2 and 3 respectively."
+  (format "\\(\\`\\|[ \t]\\)\\(%s\\)\\([ \t]\\|\\'\\)" string))
+
+(defun dired--star-or-qmark-p (string match &optional keep)
+  "Return non-nil if STRING contains isolated MATCH or `\\=`?\\=`'.
+MATCH should be the strings \"?\", `\\=`?\\=`', \"*\" or nil.  The latter
+means STRING contains either \"?\" or `\\=`?\\=`' or \"*\".
+If optional arg KEEP is non-nil, then preserve the match data.  Otherwise,
+this function changes it and saves MATCH as the second match group.
+
+Isolated means that MATCH is surrounded by spaces or at the beginning/end
+of STRING followed/prefixed with an space.  A match to `\\=`?\\=`',
+isolated or not, is also valid."
+  (let ((regexps (list (dired-isolated-string-re (if match (regexp-quote 
match) "[*?]")))))
+    (when (or (null match) (equal match "?"))
+      (setq regexps (append (list "\\(\\)\\(`\\?`\\)\\(\\)") regexps)))
+    (cl-some (lambda (x)
+               (funcall (if keep #'string-match-p #'string-match) x string))
+             regexps)))
 
 ;;;###autoload
 (defun dired-diff (file &optional switches)
@@ -658,13 +685,13 @@ If there is a `*' in COMMAND, surrounded by whitespace, 
this runs
 COMMAND just once with the entire file list substituted there.
 
 If there is no `*', but there is a `?' in COMMAND, surrounded by
-whitespace, this runs COMMAND on each file individually with the
-file name substituted for `?'.
+whitespace, or a `\\=`?\\=`' this runs COMMAND on each file
+individually with the file name substituted for `?' or `\\=`?\\=`'.
 
 Otherwise, this runs COMMAND on each file individually with the
 file name added at the end of COMMAND (separated by a space).
 
-`*' and `?' when not surrounded by whitespace have no special
+`*' and `?' when not surrounded by whitespace nor `\\=`' have no special
 significance for `dired-do-shell-command', and are passed through
 normally to the shell, but you must confirm first.
 
@@ -704,8 +731,8 @@ can be produced by `dired-get-marked-files', for example."
       (dired-read-shell-command "! on %s: " current-prefix-arg files)
       current-prefix-arg
       files)))
-  (let* ((on-each (not (string-match-p dired-star-subst-regexp command)))
-        (no-subst (not (string-match-p dired-quark-subst-regexp command)))
+  (let* ((on-each (not (dired--star-or-qmark-p command "*" 'keep)))
+        (no-subst (not (dired--star-or-qmark-p command "?" 'keep)))
         (star (string-match-p "\\*" command))
         (qmark (string-match-p "\\?" command))
          ;; Get confirmation for wildcards that may have been meant
@@ -768,12 +795,10 @@ can be produced by `dired-get-marked-files', for example."
                       ";"
                     "&"))
         (stuff-it
-         (if (or (string-match-p dired-star-subst-regexp command)
-                 (string-match-p dired-quark-subst-regexp command))
+         (if (dired--star-or-qmark-p command nil 'keep)
              (lambda (x)
                (let ((retval (concat cmd-prefix command)))
-                 (while (string-match
-                         "\\(^\\|[ \t]\\)\\([*?]\\)\\([ \t]\\|$\\)" retval)
+                 (while (dired--star-or-qmark-p retval nil)
                    (setq retval (replace-match x t t retval 2)))
                  retval))
            (lambda (x) (concat cmd-prefix command dired-mark-separator x)))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]