unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Tino Calancha <tino.calancha@gmail.com>
To: Emacs developers <emacs-devel@gnu.org>
Cc: tino.calancha@gmail.com
Subject: 26.0.50; Extend dired-do-shell-command substitutions
Date: Tue, 27 Jun 2017 00:38:00 +0900	[thread overview]
Message-ID: <87r2y6sqsn.fsf@calancha-pc> (raw)


I find convenient to extend the wildcards with one not requiring
whitespaces.

For example,
*) Assuming "`?`" is that new wildcard,
*) and there is a file "foo" at point.

Then,

! cp ? `?`-new RET g
;; Must copy "foo" into "foo-new".

How do you think?
Tino

--8<-----------------------------cut here---------------start------------->8---
commit cd9877d16edec71e7ea9b1eedd4194d67c1b092e
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Tue Jun 27 00:18:45 2017 +0900

    Extend dired-do-shell-command substitutions
    
    Substitute "`?`" inside command with the current file name.
    * lisp/dired-aux.el (dired-quark-subst-regexp, dired-star-subst-regexp):
    Delete them.
    (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.

diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 22b0fcd467..28cb51d88b 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -875,27 +875,33 @@ Shell Commands in Dired
 
 @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
+@emph{for 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:
+@example
+uuencode ? ? > `?`.uu
+@end 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/lisp/dired-aux.el b/lisp/dired-aux.el
index 121bebeb65..1265fe3501 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -49,8 +49,30 @@ dired-create-files-failures
 ;;;###begin dired-cmd.el
 ;; Diffing and compressing
 
-(defconst dired-star-subst-regexp "\\(^\\|[ \t]\\)\\*\\([ \t]\\|$\\)")
-(defconst dired-quark-subst-regexp "\\(^\\|[ \t]\\)\\?\\([ \t]\\|$\\)")
+(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)
@@ -704,8 +726,8 @@ dired-do-shell-command
       (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 +790,10 @@ dired-shell-stuff-it
                       ";"
                     "&"))
 	 (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)))))
--8<-----------------------------cut here---------------end--------------->8---

In GNU Emacs 26.0.50 (build 13, x86_64-pc-linux-gnu, GTK+ Version 3.22.11)
 of 2017-06-27 built
Repository revision: 1771d9b8082cf967e3f8b6a436d8766560be9e8d





             reply	other threads:[~2017-06-26 15:38 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-26 15:38 Tino Calancha [this message]
2017-07-01  5:06 ` 26.0.50; Extend dired-do-shell-command substitutions Tino Calancha

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87r2y6sqsn.fsf@calancha-pc \
    --to=tino.calancha@gmail.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).