From: Francis Wright <f.j.wright@live.co.uk>
To: <emacs-devel@gnu.org>
Subject: Emacs pretest list; wildcard-to-regexp
Date: Sat, 28 Apr 2012 18:21:10 +0100 [thread overview]
Message-ID: <SNT133-ds16F0398C5CCABD989307BAE52A0@phx.gbl> (raw)
[-- Attachment #1: Type: text/plain, Size: 985 bytes --]
Can you please change my email address on the pretest list from
f.j.wright@qmul.ac.uk to f.j.wright@live.co.uk? (I don't think I can do this
myself, can I?) Thanks.
About 10 years ago, I wrote a replacement for `wildcard-to-regexp' (defined
in files.el) that supports bash-style {a,b,...} expansion controlled by the
customizable option `wildcard-to-regexp-expand-{}'. I have just updated this
for Emacs 24 at the request of a user who said he has found it useful. (I
had forgotten that I ever released it, but I must have done!) I attach my
current version.
Would you like to include this modification in a future version of Emacs or
as a package? If the former then I'll provide it as a file of diffs to
files.el. If the latter then I'll provide it in the rigtht format for a
package. (If neither then I'll think about releasing it somewhere else, such
as EmacsWiki.) I have already assigned to the FSF copyright of any Emacs
modifications that I might make.
Best wishes, Francis
[-- Attachment #2: wildcard-to-regexp.el --]
[-- Type: application/octet-stream, Size: 7521 bytes --]
;;; wildcard-to-regexp.el --- with bash-style {a,b,...} expansion
;; Modified by: Francis J. Wright <f.j.wright@live.co.uk>
;; Time-stamp: <2012-04-28 17:53:03 fjw>
;;; Commentary:
;; This version of `wildcard-to-regexp' adds optional bash-style
;; {a,b,...} expansion controlled by the customizable option
;; `wildcard-to-regexp-expand-{}'. In particular, this gives users of
;; `ls-lisp' (the default version of `ls' used by non-UNIX ports of
;; Emacs) the main functionality of running `ls' under bash. (The only
;; other standard Emacs 24 packages that call `wildcard-to-regexp' are
;; `grep' and `vhdl-mode'.) It also supports escaping by \ better, but
;; quoting is not supported.
;; The function `wildcard-to-regexp' (defined in files.el) is
;; preloaded, so just byte-compile this package somewhere in your
;; `load-path' and (require 'wildcard-to-regexp) in order to redefine
;; `wildcard-to-regexp'.
;; Test examples:
;; Note that in these examples ^@ represents the ASCII NULL character.
;; Hence [^^@] represents a regexp that matches any non-NULL ASCII
;; character. (This code will probably not work correctly with
;; non-ASCII filenames!) This file contains only US-ASCII characters.
;; These examples are all expanded:
;; (wildcard-to-regexp "*.{c,h,cpp}") -> "\\`[^^@]*\\.\\(c\\|h\\|cpp\\)\\'"
;; (wildcard-to-regexp "*.{txt,texi}") -> "\\`[^^@]*\\.\\(txt\\|texi\\)\\'"
;; (wildcard-to-regexp "*.{txt,}") -> "\\`[^^@]*\\.\\(txt\\|\\)\\'"
;; (wildcard-to-regexp "*.{,txt}") -> "\\`[^^@]*\\.\\(\\|txt\\)\\'"
;; but these are not:
;; (wildcard-to-regexp "*.{txt}") -> "\\`[^^@]*\\.{txt}\\'"
;; (wildcard-to-regexp "*.{txt\\,texi}") -> "\\`[^^@]*\\.{txt\\,texi}\\'"
;; (wildcard-to-regexp "*.\\{txt,texi}") -> "\\`[^^@]*\\.\\{txt,texi}\\'"
;; From bash manual:
;; (wildcard-to-regexp "/usr/local/src/bash/{old,new,dist,bugs}") ->
;; "\\`/usr/local/src/bash/\\(old\\|new\\|dist\\|bugs\\)\\'"
;; (wildcard-to-regexp "/usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}") ->
;; "\\`/usr/\\(ucb/\\(ex\\|edit\\)\\|lib/\\(ex[^^@]\\.[^^@][^^@]*\\|how_ex\\)\\)\\'"
;;; History:
;; This file is based closely on `wildcard-to-regexp' defined in
;; `files.el', with a small addition that I originally wrote in July
;; 2001 for use with Emacs 21. I subsequently updated it in April 2012
;; for use with Emacs 24.
;;; Code:
(eval-when-compile
(require 'cl)) ; for incf, where `(incf i)' equiv `(setq i (1+ i))'
(defcustom wildcard-to-regexp-expand-{} t
"*Non-nil causes `wildcard-to-regexp' to expand {a,b,...} like bash.
This affects `grep', `ls-lisp' (which `dired' may use, see
`insert-directory') and `vhdl-mode'."
:type 'boolean
:group 'grep
:group 'ls-lisp
:group 'vhdl-mode
:version "21.2")
(defun wildcard-to-regexp (wildcard)
"Given a shell file name pattern WILDCARD, return an equivalent regexp.
The generated regexp will match a filename only if the filename
matches that wildcard according to shell rules.
If `wildcard-to-regexp-expand-{}' is non-nil then expand `{a,b,...}'
like bash, allowing arbitrary nesting. To use `{', `,' and `}' for
any other purpose they must be escaped by a preceding `\\'."
;; Shell wildcards should match the entire filename,
;; not its part. Make the regexp say so.
(concat "\\`" (wildcard-to-regexp-1 wildcard) "\\'"))
(defun wildcard-to-regexp-1 (wildcard)
"As `wildcard-to-regexp' (WILDCARD) but without the \\`...\\'.
Calls itself recursively."
(let* ((i (string-match "[[.*+\\^$?{]" wildcard))
;; Copy the initial run of non-special characters.
(result (substring wildcard 0 i))
(len (length wildcard)))
;; If no special characters, we're almost done.
(if i
(while (< i len)
(let ((ch (aref wildcard i))
j)
(setq
result
(concat result
(cond
((and (eq ch ?\[)
(< (1+ i) len)
(eq (aref wildcard (1+ i)) ?\]))
"\\[")
((eq ch ?\[) ; [...] maps to regexp char class
(incf i)
(concat
(cond
((eq (aref wildcard i) ?!) ; [!...] -> [^...]
(incf i)
(if (eq (aref wildcard i) ?\])
(progn
(incf i)
"[^]")
"[^"))
((eq (aref wildcard i) ?^)
;; Found "[^". Insert a `\0' character
;; (which cannot happen in a filename)
;; into the character class, so that `^'
;; is not the first character after `[',
;; and thus non-special in a regexp.
(incf i)
"[\000^")
((eq (aref wildcard i) ?\])
;; I don't think `]' can appear in a
;; character class in a wildcard, but
;; let's be general here.
(incf i)
"[]")
(t "["))
(prog1 ; copy everything upto next `]'.
(substring wildcard
i
(setq j (string-match
"]" wildcard i)))
(setq i (if j (1- j) (1- len))))))
((eq ch ?.) "\\.")
((eq ch ?*) "[^\000]*")
((eq ch ?+) "\\+")
((eq ch ?^) "\\^")
((eq ch ?$) "\\$")
((eq ch ?\\) ; FJW
(incf i)
(if (< i len)
(concat "\\" (char-to-string (aref wildcard i)))
"\\\\"))
((eq ch ??) "[^\000]")
((and (eq ch ?{)
wildcard-to-regexp-expand-{})
;; FJW: {a,b,...} -> \(a\|b\|...\)
;; Return regexp equivalent to bash
;; `{a,b,...}'-pattern in string wildcard
;; beginning at index i.
;; [Note that wildcard-to-regexp-find-\,} start
;; index must allow for a preceding character
;; [^\], and so is i rather than (1+ i), etc.]
;; Find first comma:
(let (s j ii)
(if (not (and (setq j (wildcard-to-regexp-find-\,} wildcard i))
(eq (aref wildcard j) ?,)))
"{" ; does not match {a,...}
(setq s (concat "\\(" ; Emacs 21: use shy group "\\(?:" ?
(wildcard-to-regexp-1
(substring wildcard (1+ i) j)))
ii j)
;; Find subsequent commas or closing brace:
(while (and (setq j (wildcard-to-regexp-find-\,} wildcard ii))
(eq (aref wildcard j) ?,))
(setq s (concat s "\\|"
(wildcard-to-regexp-1
(substring wildcard (1+ ii) j)))
ii j))
;; Found closing brace or failed:
(cond
(j (setq s (concat s "\\|"
(wildcard-to-regexp-1
(substring wildcard (1+ ii) j)))
i j) ; update i
(concat s "\\)")) ; return regexp
(t "{")) ; does not match {a,...}
)))
(t (char-to-string ch)))))
(incf i))))
result))
(defun wildcard-to-regexp-find-\,} (s i)
"Return index of first top-level `,' or `}' after `{' in string S at index I.
Allow nested `{...}' and ignore characters escaped by a preceding `\\'."
(setq i (string-match "[^\\][{,}]" s i))
(while (and i (eq (aref s (1+ i)) ?{))
(setq i (wildcard-to-regexp-skip-{} s (1+ i)))
(if i (setq i (string-match "[^\\][{,}]" s i))))
(and i (1+ i)))
(defun wildcard-to-regexp-skip-{} (s i)
"Return index of `}' matching `{' in string S at index I.
Allow nested `{...}' and ignore characters escaped by a preceding `\\'."
(setq i (string-match "[^\\][{}]" s i))
(while (and i (eq (aref s (1+ i)) ?{))
(setq i (wildcard-to-regexp-skip-{} s (1+ i)))
(if i (setq i (string-match "[^\\][{}]" s i))))
(and i (1+ i)))
(provide 'wildcard-to-regexp)
;;; wildcard-to-regexp.el ends here
next reply other threads:[~2012-04-28 17:21 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-28 17:21 Francis Wright [this message]
2012-04-28 18:54 ` Emacs pretest list; wildcard-to-regexp Eli Zaretskii
2012-04-29 6:43 ` Chong Yidong
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=SNT133-ds16F0398C5CCABD989307BAE52A0@phx.gbl \
--to=f.j.wright@live.co.uk \
--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).