commit c1173f231d46f14f71886fa343dbc7501f064919 (HEAD, refs/remotes/origin/master) Author: Stefan Kangas Date: Wed Apr 7 01:49:21 2021 +0200 ; Fix my previous change to shadowfile.el * lisp/shadowfile.el (shadow-add-to-todo, shadow-union): Wrap call to cl-union in nreverse for backwards-compatible ordering. diff --git a/lisp/shadowfile.el b/lisp/shadowfile.el index a03965cf6c..b5e7d444c5 100644 --- a/lisp/shadowfile.el +++ b/lisp/shadowfile.el @@ -639,7 +639,7 @@ Consider them as regular expressions if third arg REGEXP is true." shadows shadow-files-to-copy (with-output-to-string (backtrace)))) (when shadows (setq shadow-files-to-copy - (cl-union shadows shadow-files-to-copy :test #'equal)) + (nreverse (cl-union shadows shadow-files-to-copy :test #'equal))) (when (not shadow-inhibit-message) (message "%s" (substitute-command-keys "Use \\[shadow-copy-files] to update shadows.")) @@ -832,7 +832,7 @@ look for files that have been changed and need to be copied to other systems." (defun shadow-union (a b) "Add members of list A to list B if not equal to items already in B." (declare (obsolete cl-union "28.1")) - (cl-union a b :test #'equal)) + (nreverse (cl-union a b :test #'equal))) (define-obsolete-function-alias 'shadow-find #'seq-find "28.1") commit 1ff7cde1027778e608acbe58a81fe08c1fd84189 Author: Dmitry Gutov Date: Wed Apr 7 03:24:17 2021 +0300 Add explicit support for C-g or ESC ESC ESC after keymap prompt * lisp/progmodes/project.el (project-switch-project): Add explicit support for C-g or ESC ESC ESC after keymap prompt (bug#47620). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 84d02e25d9..a819e7243c 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1363,7 +1363,11 @@ to directory DIR." (assq command commands-menu)) ;; TODO: Add some hint to the prompt, like "key not ;; recognized" or something. - (setq command nil))))) + (setq command nil))) + (let ((global-command (lookup-key (current-global-map) choice))) + (when (memq global-command + '(keyboard-quit keyboard-escape-quit)) + (call-interactively global-command))))) (let ((default-directory dir) (project-current-inhibit-prompt t)) (call-interactively command)))) commit 5d293f4f7489bcc9659f69f41e8db2a0755e5f44 Author: Dario Gjorgjevski Date: Tue Apr 6 16:51:28 2021 +0200 Allow complex key bindings in project-switch-project * lisp/progmodes/project.el (project-switch-project): Replace read-event with an overriding local map and read-key-sequence to allow for complex key bindings to be read (bug#47620). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 910f70db03..84d02e25d9 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1338,23 +1338,27 @@ made from `project-switch-commands'. When called in a program, it will use the project corresponding to directory DIR." (interactive (list (project-prompt-project-dir))) - (let ((commands-menu - (mapcar - (lambda (row) - (if (characterp (car row)) - ;; Deprecated format. - ;; XXX: Add a warning about it? - (reverse row) - row)) - project-switch-commands)) - command) + (let* ((commands-menu + (mapcar + (lambda (row) + (if (characterp (car row)) + ;; Deprecated format. + ;; XXX: Add a warning about it? + (reverse row) + row)) + project-switch-commands)) + (commands-map + (let ((temp-map (make-sparse-keymap))) + (set-keymap-parent temp-map project-prefix-map) + (dolist (row commands-menu temp-map) + (when-let ((cmd (nth 0 row)) + (keychar (nth 2 row))) + (define-key temp-map (vector keychar) cmd))))) + command) (while (not command) - (let ((choice (read-event (project--keymap-prompt)))) - (when (setq command - (or (car - (seq-find (lambda (row) (equal choice (nth 2 row))) - commands-menu)) - (lookup-key project-prefix-map (vector choice)))) + (let ((overriding-local-map commands-map) + (choice (read-key-sequence (project--keymap-prompt)))) + (when (setq command (lookup-key commands-map choice)) (unless (or project-switch-use-entire-map (assq command commands-menu)) ;; TODO: Add some hint to the prompt, like "key not commit c105017c44d4a679f7af739b2c0390b2c7850569 Author: Stefan Monnier Date: Tue Apr 6 17:06:07 2021 -0400 * lisp/find-file.el: Make the commands oblivious to mouse/non-mouse (ff-find-other-file): Add `event` argument. (ff-find-other-file-other-window): Rename from `ff-mouse-find-other-file-other-window` and use this new argument. (ff-mouse-find-other-file, ff-mouse-find-other-file-other-window): Make them obsolete aliases. (ff-upcase-p): Remove unused `start` and `end` arguments and simplify accordingly. diff --git a/lisp/find-file.el b/lisp/find-file.el index d54fdffadb..6c3c0f123b 100644 --- a/lisp/find-file.el +++ b/lisp/find-file.el @@ -298,7 +298,7 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window." (defalias 'ff-find-related-file #'ff-find-other-file) ;;;###autoload -(defun ff-find-other-file (&optional in-other-window ignore-include) +(defun ff-find-other-file (&optional in-other-window ignore-include event) "Find the header or source file corresponding to this file. Being on a `#include' line pulls in that file. @@ -350,9 +350,11 @@ Variables of interest include: - `ff-file-created-hook' List of functions to be called if the other file has been created." - (interactive "P") - (let ((ff-ignore-include ignore-include)) - (ff-find-the-other-file in-other-window))) + (interactive (list current-prefix-arg nil last-nonmenu-event)) + (save-excursion + (posn-set-point (event-end event)) + (let ((ff-ignore-include ignore-include)) + (ff-find-the-other-file in-other-window)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Support functions @@ -734,42 +736,26 @@ called before `ff-post-load-hook'." buffer-or-name in-other-window nil)) ;;;###autoload -(defun ff-mouse-find-other-file (event) - "Visit the file you click on." - (interactive "e") - (save-excursion - (mouse-set-point event) - (ff-find-other-file nil))) +(define-obsolete-function-alias + 'ff-mouse-find-other-file #'ff-find-other-file "28.1") ;;;###autoload -(defun ff-mouse-find-other-file-other-window (event) - "Visit the file you click on in another window." - (interactive "e") - (save-excursion - (mouse-set-point event) - (ff-find-other-file t))) +(define-obsolete-function-alias + 'ff-mouse-find-other-file-other-window #'ff-find-other-file-other-window "28.1") +;;;###autoload +(defun ff-find-other-file-other-window (event) + "Visit the file you point at in another window." + (interactive (list last-nonmenu-event)) + (ff-find-other-file t nil event)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This section offers an example of user defined function to select files -(defun ff-upcase-p (string &optional start end) - "Return t if STRING is all uppercase. -Given START and/or END, checks between these characters." - (let (match str) - (if (not start) - (setq start 0)) - (if (not end) - (setq end (length string))) - (if (= start end) - (setq end (1+ end))) - (setq str (substring string start end)) - (if (and - (ff-string-match "[[:upper:]]+" str) - (setq match (match-data)) - (= (car match) 0) - (= (car (cdr match)) (length str))) - t - nil))) +(defun ff-upcase-p (string) + "Return t if STRING is all uppercase." + ;; FIXME: Why `ff-string-match' since `[:upper:]' only makes + ;; sense when `case-fold-search' is nil? + (ff-string-match "\\`[[:upper:]]*\\'" string)) (defun ff-cc-hh-converter (arg) "Discriminate file extensions. commit c9655fcb47da8a104eb7b5eb7a3d0b4a6ba26fc3 Author: Stefan Monnier Date: Tue Apr 6 16:28:50 2021 -0400 * lisp/find-file.el: Use lexical-binding Remove unused `:group` args. Prefer #' to quote function. (ff-special-constructs, ff-find-the-other-file, ff-get-file-name) (ff-list-replace-env-vars, ff-cc-hh-converter): Use `match-string`. (modula2-other-file-alist): Tighten regexps. (ff-get-other-file, ff-find-other-file): Use dynamic scoping. (ff-find-the-other-file): Minor simplification. (ff-other-file-name): Delete unused function. (ff-string-match): Don't let-bind `case-fold-search` if not needed. (ff-basename): Make it an obsolete alias for `file-name-nondirectory`. (ff-switch-file): Minor simplification. (ff-list-replace-env-vars): Use [:alnum:]. (ff-upcase-p): Use [:upper:] (ff-cc-hh-converter): Use [:upper:] and [:lower:]. diff --git a/lisp/find-file.el b/lisp/find-file.el index 8cc9c972ed..d54fdffadb 100644 --- a/lisp/find-file.el +++ b/lisp/find-file.el @@ -1,4 +1,4 @@ -;;; find-file.el --- find a file corresponding to this one given a pattern +;;; find-file.el --- find a file corresponding to this one given a pattern -*- lexical-binding: t; -*- ;; Author: Henry Guillaume ;; Maintainer: emacs-devel@gnu.org @@ -39,8 +39,8 @@ ;; and just has a different extension as described by the ff-other-file-alist ;; variable: ;; -;; '(("\\.cc$" (".hh" ".h")) -;; ("\\.hh$" (".cc" ".C" ".CC" ".cxx" ".cpp"))) +;; '(("\\.cc\\'" (".hh" ".h")) +;; ("\\.hh\\'" (".cc" ".C" ".CC" ".cxx" ".cpp"))) ;; ;; If the current file has a .cc extension, ff-find-other-file will attempt ;; to look for a .hh file, and then a .h file in some directory as described @@ -55,8 +55,8 @@ ;; format above can be changed to include a function to be called when the ;; current file matches the regexp: ;; -;; '(("\\.cc$" cc--function) -;; ("\\.hh$" hh-function)) +;; '(("\\.cc\\'" cc--function) +;; ("\\.hh\\'" hh-function)) ;; ;; These functions must return a list consisting of the possible names of the ;; corresponding file, with or without path. There is no real need for more @@ -64,10 +64,10 @@ ;; file-alist: ;; ;; (setq cc-other-file-alist -;; '(("\\.cc$" ff-cc-hh-converter) -;; ("\\.hh$" ff-cc-hh-converter) -;; ("\\.c$" (".h")) -;; ("\\.h$" (".c" ".cc" ".C" ".CC" ".cxx" ".cpp")))) +;; '(("\\.cc\\'" ff-cc-hh-converter) +;; ("\\.hh\\'" ff-cc-hh-converter) +;; ("\\.c\\'" (".h")) +;; ("\\.h\\'" (".c" ".cc" ".C" ".CC" ".cxx" ".cpp")))) ;; ;; ff-cc-hh-converter is included at the end of this file as a reference. ;; @@ -130,62 +130,51 @@ (defcustom ff-pre-find-hook nil "List of functions to be called before the search for the file starts." - :type 'hook - :group 'ff) + :type 'hook) (defcustom ff-pre-load-hook nil "List of functions to be called before the other file is loaded." - :type 'hook - :group 'ff) + :type 'hook) (defcustom ff-post-load-hook nil "List of functions to be called after the other file is loaded." - :type 'hook - :group 'ff) + :type 'hook) (defcustom ff-not-found-hook nil "List of functions to be called if the other file could not be found." - :type 'hook - :group 'ff) + :type 'hook) (defcustom ff-file-created-hook nil "List of functions to be called if the other file needs to be created." - :type 'hook - :group 'ff) + :type 'hook) (defcustom ff-case-fold-search nil "Non-nil means ignore cases in matches (see `case-fold-search'). If you have extensions in different cases, you will want this to be nil." - :type 'boolean - :group 'ff) + :type 'boolean) (defcustom ff-always-in-other-window nil "If non-nil, find the corresponding file in another window by default. To override this, give an argument to `ff-find-other-file'." - :type 'boolean - :group 'ff) + :type 'boolean) (defcustom ff-ignore-include nil "If non-nil, ignore `#include' lines." - :type 'boolean - :group 'ff) + :type 'boolean) (defcustom ff-always-try-to-create t "If non-nil, always attempt to create the other file if it was not found." - :type 'boolean - :group 'ff) + :type 'boolean) (defcustom ff-quiet-mode nil "If non-nil, trace which directories are being searched." - :type 'boolean - :group 'ff) + :type 'boolean) ;;;###autoload (defcustom ff-special-constructs ;; C/C++ include, for NeXTstep too `((,(purecopy "^#\\s *\\(include\\|import\\)\\s +[<\"]\\(.*\\)[>\"]") . - (lambda () - (buffer-substring (match-beginning 2) (match-end 2))))) + ,(lambda () (match-string 2)))) ;; We include `ff-treat-as-special' documentation here so that autoload ;; can make it available to be read prior to loading this file. "List of special constructs recognized by `ff-treat-as-special'. @@ -194,8 +183,7 @@ If REGEXP matches the current line (from the beginning of the line), `ff-treat-as-special' calls function EXTRACT with no args. If EXTRACT returns nil, keep trying. Otherwise, return the filename that EXTRACT returned." - :type '(repeat (cons regexp function)) - :group 'ff) + :type '(repeat (cons regexp function))) (defvaralias 'ff-related-file-alist 'ff-other-file-alist) (defcustom ff-other-file-alist 'cc-other-file-alist @@ -207,8 +195,7 @@ directory specified in `ff-search-directories'. If a file is not found, a new one is created with the first matching extension (`.cc' yields `.hh'). This alist should be set by the major mode." :type '(choice (repeat (list regexp (choice (repeat string) function))) - symbol) - :group 'ff) + symbol)) (defcustom ff-search-directories 'cc-search-directories "List of directories to search for a specific file. @@ -231,14 +218,12 @@ not exist, it is replaced (silently) with an empty string. The stars are *not* wildcards: they are searched for together with the preceding slash. The star represents all the subdirectories except `..', and each of these subdirectories will be searched in turn." - :type '(choice (repeat directory) symbol) - :group 'ff) + :type '(choice (repeat directory) symbol)) (defcustom cc-search-directories '("." "/usr/include" "/usr/local/include/*") "See the description of the `ff-search-directories' variable." - :type '(repeat directory) - :group 'ff) + :type '(repeat directory)) (defcustom cc-other-file-alist '(("\\.cc\\'" (".hh" ".h")) @@ -269,17 +254,15 @@ since the search algorithm searches sequentially through each directory specified in `ff-search-directories'. If a file is not found, a new one is created with the first matching extension (`.cc' yields `.hh')." :version "24.4" ; add .m - :type '(repeat (list regexp (choice (repeat string) function))) - :group 'ff) + :type '(repeat (list regexp (choice (repeat string) function)))) (defcustom modula2-other-file-alist '( - ("\\.mi$" (".md")) ;; Modula-2 module definition - ("\\.md$" (".mi")) ;; and implementation. + ("\\.mi\\'" (".md")) ;; Modula-2 module definition + ("\\.md\\'" (".mi")) ;; and implementation. ) "See the description for the `ff-search-directories' variable." - :type '(repeat (list regexp (choice (repeat string) function))) - :group 'ff) + :type '(repeat (list regexp (choice (repeat string) function)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -308,13 +291,11 @@ See also the documentation for `ff-find-other-file'. If optional IN-OTHER-WINDOW is non-nil, find the file in another window." (interactive "P") - (let ((ignore ff-ignore-include)) - (setq ff-ignore-include t) - (ff-find-the-other-file in-other-window) - (setq ff-ignore-include ignore))) + (let ((ff-ignore-include t)) + (ff-find-the-other-file in-other-window))) ;;;###autoload -(defalias 'ff-find-related-file 'ff-find-other-file) +(defalias 'ff-find-related-file #'ff-find-other-file) ;;;###autoload (defun ff-find-other-file (&optional in-other-window ignore-include) @@ -370,10 +351,8 @@ Variables of interest include: - `ff-file-created-hook' List of functions to be called if the other file has been created." (interactive "P") - (let ((ignore ff-ignore-include)) - (setq ff-ignore-include ignore-include) - (ff-find-the-other-file in-other-window) - (setq ff-ignore-include ignore))) + (let ((ff-ignore-include ignore-include)) + (ff-find-the-other-file in-other-window))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Support functions @@ -413,9 +392,9 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window." (message "Working...") (setq dirs - (if (symbolp ff-search-directories) - (ff-list-replace-env-vars (symbol-value ff-search-directories)) - (ff-list-replace-env-vars ff-search-directories))) + (ff-list-replace-env-vars (if (symbolp ff-search-directories) + (symbol-value ff-search-directories) + ff-search-directories))) (setq fname (ff-treat-as-special)) @@ -454,11 +433,10 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window." ;; if we have a function to generate new names, ;; invoke it with the name of the current file (if (and (atom action) (fboundp action)) - (progn - (setq suffixes (funcall action (ff-buffer-file-name)) - match (cons (car match) (list suffixes)) - stub nil - default-name (car suffixes))) + (setq suffixes (funcall action (ff-buffer-file-name)) + match (cons (car match) (list suffixes)) + stub nil + default-name (car suffixes)) ;; otherwise build our filename stub (cond @@ -472,7 +450,8 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window." (t (setq format (concat "\\(.+\\)" (car match))) (string-match format fname) - (setq stub (substring fname (match-beginning 1) (match-end 1))) + ;; FIXME: What if `string-match' failed? + (setq stub (match-string 1 fname)) )) ;; if we find nothing, we should try to get a file like this one @@ -522,89 +501,6 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window." found)) ;; return buffer-name or filename -(defun ff-other-file-name () - "Return name of the header or source file corresponding to the current file. -Being on a `#include' line pulls in that file, but see the help on -the `ff-ignore-include' variable." - - (let (match ;; matching regexp for this file - suffixes ;; set of replacing regexps for the matching regexp - action ;; function to generate the names of the other files - fname ;; basename of this file - pos ;; where we start matching filenames - stub ;; name of the file without extension - alist ;; working copy of the list of file extensions - pathname ;; the pathname of the file or the #include line - format ;; what we have to match - found ;; name of the file or buffer found - nil if none - dirs) ;; local value of ff-search-directories - - (message "Working...") - - (setq dirs - (if (symbolp ff-search-directories) - (ff-list-replace-env-vars (symbol-value ff-search-directories)) - (ff-list-replace-env-vars ff-search-directories))) - - (setq fname (ff-treat-as-special)) - - (cond - ((and (not ff-ignore-include) fname) - (setq found (ff-get-file-name dirs fname nil))) - - ;; let's just get the corresponding file - (t - (setq alist (if (symbolp ff-other-file-alist) - (symbol-value ff-other-file-alist) - ff-other-file-alist) - pathname (or (ff-buffer-file-name) "/none.none")) - - (setq fname (file-name-nondirectory pathname) - match (car alist)) - - ;; find the table entry corresponding to this file - (setq pos (ff-string-match (car match) fname)) - (while (and match (if (and pos (>= pos 0)) nil (not pos))) - (setq alist (cdr alist)) - (setq match (car alist)) - (setq pos (ff-string-match (car match) fname))) - - ;; no point going on if we haven't found anything - (when match - - ;; otherwise, suffixes contains what we need - (setq suffixes (car (cdr match)) - action (car (cdr match)) - found nil) - - ;; if we have a function to generate new names, - ;; invoke it with the name of the current file - (if (and (atom action) (fboundp action)) - (progn - (setq suffixes (funcall action (ff-buffer-file-name)) - match (cons (car match) (list suffixes)) - stub nil)) - - ;; otherwise build our filename stub - (cond - - ;; get around the problem that 0 and nil both mean false! - ((= pos 0) - (setq format "") - (setq stub "") - ) - - (t - (setq format (concat "\\(.+\\)" (car match))) - (string-match format fname) - (setq stub (substring fname (match-beginning 1) (match-end 1))) - ))) - - ;; do the real work - find the file - (setq found - (ff-get-file-name dirs stub suffixes))))) - found)) ;; return buffer-name or filename - (defun ff-get-file (search-dirs filename &optional suffix-list other-window) "Find a file in the SEARCH-DIRS with the given FILENAME (or filename stub). If (optional) SUFFIX-LIST is nil, search for FILENAME, otherwise search @@ -709,11 +605,10 @@ name of the first file found." ;; otherwise dir matches the '/*', so search each dir separately (progn - (if (match-beginning 2) - (setq rest (substring dir (match-beginning 2) (match-end 2))) - (setq rest "") - ) - (setq dir (substring dir (match-beginning 1) (match-end 1))) + (setq rest (if (match-beginning 2) + (match-string 2 dir) + "")) + (setq dir (match-string 1 dir)) (let ((dirlist (ff-all-dirs-under dir '(".."))) this-dir compl-dirs) @@ -743,8 +638,8 @@ name of the first file found." (defun ff-string-match (regexp string &optional start) "Like `string-match', but set `case-fold-search' temporarily. The value used comes from `ff-case-fold-search'." - (let ((case-fold-search ff-case-fold-search)) - (if regexp + (if regexp + (let ((case-fold-search ff-case-fold-search)) (string-match regexp string start)))) (defun ff-list-replace-env-vars (search-list) @@ -752,12 +647,12 @@ The value used comes from `ff-case-fold-search'." (let (list (var (car search-list))) (while search-list - (if (string-match "\\(.*\\)\\$[({]*\\([a-zA-Z0-9_]+\\)[)}]*\\(.*\\)" var) + (if (string-match "\\(.*\\)\\$[({]*\\([[:alnum:]_]+\\)[)}]*\\(.*\\)" var) (setq var (concat - (substring var (match-beginning 1) (match-end 1)) - (getenv (substring var (match-beginning 2) (match-end 2))) - (substring var (match-beginning 3) (match-end 3))))) + (match-string 1 var) + (getenv (match-string 2 var)) + (match-string 3 var)))) (setq search-list (cdr search-list)) (setq list (cons var list)) (setq var (car search-list))) @@ -782,11 +677,7 @@ See variable `ff-special-constructs'." (setq match (cdr elem))) fname))) -(defun ff-basename (string) - "Return the basename of pathname STRING." - (setq string (concat "/" string)) - (string-match ".*/\\([^/]+\\)$" string) - (setq string (substring string (match-beginning 1) (match-end 1)))) +(define-obsolete-function-alias 'ff-basename #'file-name-nondirectory "28.1") (defun ff-all-dirs-under (here &optional exclude) "Get all the directory files under directory HERE. @@ -800,7 +691,7 @@ Exclude all files in the optional EXCLUDE list." (setq file (car files)) (if (and (file-directory-p file) - (not (member (ff-basename file) exclude))) + (not (member (file-name-nondirectory file) exclude))) (setq dirlist (cons file dirlist))) (setq files (cdr files))) (setq dirlist (reverse dirlist)))) @@ -820,26 +711,26 @@ or `switch-to-buffer' / `switch-to-buffer-other-window' function pairs. If optional NEW-FILE is t, then a special hook (`ff-file-created-hook') is called before `ff-post-load-hook'." (run-hooks 'ff-pre-load-hook 'ff-pre-load-hooks) - (if (or - (and in-other-window (not ff-always-in-other-window)) - (and (not in-other-window) ff-always-in-other-window)) - (funcall f2 file) - (funcall f1 file)) + (funcall (if (or + (and in-other-window (not ff-always-in-other-window)) + (and (not in-other-window) ff-always-in-other-window)) + f2 f1) + file) (if new-file (run-hooks 'ff-file-created-hook 'ff-file-created-hooks)) (run-hooks 'ff-post-load-hook 'ff-post-load-hooks)) (defun ff-find-file (file &optional in-other-window new-file) "Like `find-file', but may show the file in another window." - (ff-switch-file 'find-file - 'find-file-other-window + (ff-switch-file #'find-file + #'find-file-other-window file in-other-window new-file)) (defun ff-switch-to-buffer (buffer-or-name &optional in-other-window) "Like `switch-to-buffer', but may show the buffer in another window." - (ff-switch-file 'switch-to-buffer - 'switch-to-buffer-other-window + (ff-switch-file #'switch-to-buffer + #'switch-to-buffer-other-window buffer-or-name in-other-window nil)) ;;;###autoload @@ -873,7 +764,7 @@ Given START and/or END, checks between these characters." (setq end (1+ end))) (setq str (substring string start end)) (if (and - (ff-string-match "[A-Z]+" str) + (ff-string-match "[[:upper:]]+" str) (setq match (match-data)) (= (car match) 0) (= (car (cdr match)) (length str))) @@ -885,19 +776,16 @@ Given START and/or END, checks between these characters." Build up a new file list based possibly on part of the directory name and the name of the file passed in." (ff-string-match "\\(.*\\)/\\([^/]+\\)/\\([^.]+\\).\\([^/]+\\)$" arg) - (let ((dire (if (match-beginning 2) - (substring arg (match-beginning 2) (match-end 2)) nil)) - (file (if (match-beginning 3) - (substring arg (match-beginning 3) (match-end 3)) nil)) - (extn (if (match-beginning 4) - (substring arg (match-beginning 4) (match-end 4)) nil)) + (let ((dire (match-string 2 arg)) + (file (match-string 3 arg)) + (extn (match-string 4 arg)) return-list) (cond ;; fooZapJunk.cc => ZapJunk.{hh,h} or fooZapJunk.{hh,h} ((and (string= extn "cc") - (ff-string-match "^\\([a-z]+\\)\\([A-Z].+\\)$" file)) - (let ((stub (substring file (match-beginning 2) (match-end 2)))) - (setq dire (upcase (substring file (match-beginning 1) (match-end 1)))) + (ff-string-match "^\\([[:lower:]]+\\)\\([[:upper:]].+\\)$" file)) + (let ((stub (match-string 2 file))) + (setq dire (upcase (match-string 1 file))) (setq return-list (list (concat stub ".hh") (concat stub ".h") (concat file ".hh") commit 735ed235c7edb4a487bda9375808ec29d4bea0fb Author: Juri Linkov Date: Tue Apr 6 22:15:30 2021 +0300 * lisp/isearch.el (isearch-wrap-pause): New defcustom (bug#47599). (isearch-repeat): Use it. (isearch-search): Don't ding when isearch-wrap-pause is no-ding. diff --git a/etc/NEWS b/etc/NEWS index c8400ba8c2..d3a8748ded 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -929,6 +929,14 @@ take the actual screenshot, and defaults to "ImageMagick import". A server entry retrieved by auth-source can request a desired smtp authentication mechanism by setting a value for the key 'smtp-auth'. +** Search and Replace + +*** New user option 'isearch-wrap-pause' defines how to wrap the search. +There are choices to disable wrapping completely and to wrap immediately. +When wrapping immediately, it consistently handles the numeric arguments +of 'C-s' ('isearch-repeat-forward') and 'C-r' ('isearch-repeat-backward'), +continuing with the remaining count after wrapping. + ** Grep +++ diff --git a/lisp/isearch.el b/lisp/isearch.el index 943e24aa56..a828c569aa 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -172,6 +172,19 @@ This allows you to resume earlier Isearch sessions through the command history." :type 'boolean) +(defcustom isearch-wrap-pause t + "Define the behavior of wrapping when there are no more matches. +When `t' (by default), signal an error when no more matches are found. +Then after repeating the search, wrap with `isearch-wrap-function'. +When `no', wrap immediately after reaching the last match. +When `no-ding', wrap immediately without flashing the screen. +When `nil', never wrap, just stop at the last match." + :type '(choice (const :tag "Pause before wrapping" t) + (const :tag "No pause before wrapping" no) + (const :tag "No pause and no flashing" no-ding) + (const :tag "Disable wrapping" nil)) + :version "28.1") + (defvar isearch-mode-hook nil "Function(s) to call after starting up an incremental search.") @@ -1827,13 +1840,12 @@ Use `isearch-exit' to quit without signaling." ;; After taking the last element, adjust ring to previous one. (isearch-ring-adjust1 nil)) ;; If already have what to search for, repeat it. - (or isearch-success - (progn - ;; Set isearch-wrapped before calling isearch-wrap-function - (setq isearch-wrapped t) - (if isearch-wrap-function - (funcall isearch-wrap-function) - (goto-char (if isearch-forward (point-min) (point-max))))))) + (unless (or isearch-success (null isearch-wrap-pause)) + ;; Set isearch-wrapped before calling isearch-wrap-function + (setq isearch-wrapped t) + (if isearch-wrap-function + (funcall isearch-wrap-function) + (goto-char (if isearch-forward (point-min) (point-max)))))) ;; C-s in reverse or C-r in forward, change direction. (setq isearch-forward (not isearch-forward) isearch-success t)) @@ -1844,7 +1856,8 @@ Use `isearch-exit' to quit without signaling." (setq isearch-success t) ;; For the case when count > 1, don't keep intermediate states ;; added to isearch-cmds by isearch-push-state in this loop. - (let ((isearch-cmds isearch-cmds)) + (let ((isearch-cmds isearch-cmds) + (was-success isearch-success)) (while (<= 0 (setq count (1- (or count 1)))) (if (and isearch-success (equal (point) isearch-other-end) @@ -1859,13 +1872,28 @@ Use `isearch-exit' to quit without signaling." (forward-char (if isearch-forward 1 -1)) (isearch-search)) (isearch-search)) - (when (> count 0) - ;; Update isearch-cmds, so if isearch-search fails later, - ;; it can restore old successful state from isearch-cmds. - (isearch-push-state)) - ;; Stop looping on failure. - (when (or (not isearch-success) isearch-error) - (setq count 0))))) + (when (> count 0) + ;; Update isearch-cmds, so if isearch-search fails later, + ;; it can restore old successful state from isearch-cmds. + (isearch-push-state)) + (cond + ;; Wrap immediately and repeat the search again + ((memq isearch-wrap-pause '(no no-ding)) + (if isearch-success + (setq was-success isearch-success) + ;; If failed this time after succeeding last time + (when was-success + (setq was-success nil) + (setq count (1+ count)) ;; Increment to force repeat + (setq isearch-wrapped t) + (if isearch-wrap-function + ;; Note that some wrap functions change the value of + ;; isearch-success, so it's handled above before this call. + (funcall isearch-wrap-function) + (goto-char (if isearch-forward (point-min) (point-max))))))) + ;; Stop looping on failure + (t (when (or (not isearch-success) isearch-error) + (setq count 0))))))) (isearch-push-state) (isearch-update)) @@ -3488,10 +3516,10 @@ Optional third argument, if t, means if fail just return nil (no error). ;; stack overflow in regexp search. (setq isearch-error (format "%s" lossage)))) - (if isearch-success - nil + (unless isearch-success ;; Ding if failed this time after succeeding last time. (and (isearch--state-success (car isearch-cmds)) + (not (eq isearch-wrap-pause 'no-ding)) (ding)) (if (functionp (isearch--state-pop-fun (car isearch-cmds))) (funcall (isearch--state-pop-fun (car isearch-cmds)) commit ccd616aeb0519e936bc0064709d32905b5597859 Author: Stefan Monnier Date: Tue Apr 6 14:05:58 2021 -0400 * lisp/progmodes/ps-mode.el: Use lexical-binding And prefer #' to quote function names. diff --git a/lisp/progmodes/ps-mode.el b/lisp/progmodes/ps-mode.el index 598f748f5b..67c034d090 100644 --- a/lisp/progmodes/ps-mode.el +++ b/lisp/progmodes/ps-mode.el @@ -1,4 +1,4 @@ -;;; ps-mode.el --- PostScript mode for GNU Emacs +;;; ps-mode.el --- PostScript mode for GNU Emacs -*- lexical-binding: t; -*- ;; Copyright (C) 1999, 2001-2021 Free Software Foundation, Inc. @@ -281,20 +281,20 @@ If nil, use `temporary-file-directory'." (defvar ps-mode-map (let ((map (make-sparse-keymap))) - (define-key map "\C-c\C-v" 'ps-run-boundingbox) - (define-key map "\C-c\C-u" 'ps-mode-uncomment-region) - (define-key map "\C-c\C-t" 'ps-mode-epsf-rich) - (define-key map "\C-c\C-s" 'ps-run-start) - (define-key map "\C-c\C-r" 'ps-run-region) - (define-key map "\C-c\C-q" 'ps-run-quit) - (define-key map "\C-c\C-p" 'ps-mode-print-buffer) - (define-key map "\C-c\C-o" 'ps-mode-comment-out-region) - (define-key map "\C-c\C-k" 'ps-run-kill) - (define-key map "\C-c\C-j" 'ps-mode-other-newline) - (define-key map "\C-c\C-l" 'ps-run-clear) - (define-key map "\C-c\C-b" 'ps-run-buffer) + (define-key map "\C-c\C-v" #'ps-run-boundingbox) + (define-key map "\C-c\C-u" #'ps-mode-uncomment-region) + (define-key map "\C-c\C-t" #'ps-mode-epsf-rich) + (define-key map "\C-c\C-s" #'ps-run-start) + (define-key map "\C-c\C-r" #'ps-run-region) + (define-key map "\C-c\C-q" #'ps-run-quit) + (define-key map "\C-c\C-p" #'ps-mode-print-buffer) + (define-key map "\C-c\C-o" #'ps-mode-comment-out-region) + (define-key map "\C-c\C-k" #'ps-run-kill) + (define-key map "\C-c\C-j" #'ps-mode-other-newline) + (define-key map "\C-c\C-l" #'ps-run-clear) + (define-key map "\C-c\C-b" #'ps-run-buffer) ;; FIXME: Add `indent' to backward-delete-char-untabify-method instead? - (define-key map "\177" 'ps-mode-backward-delete-char) + (define-key map "\177" #'ps-mode-backward-delete-char) map) "Local keymap to use in PostScript mode.") @@ -336,10 +336,10 @@ If nil, use `temporary-file-directory'." (defvar ps-run-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map comint-mode-map) - (define-key map "\C-c\C-q" 'ps-run-quit) - (define-key map "\C-c\C-k" 'ps-run-kill) - (define-key map "\C-c\C-e" 'ps-run-goto-error) - (define-key map [mouse-2] 'ps-run-mouse-goto-error) + (define-key map "\C-c\C-q" #'ps-run-quit) + (define-key map "\C-c\C-k" #'ps-run-kill) + (define-key map "\C-c\C-e" #'ps-run-goto-error) + (define-key map [mouse-2] #'ps-run-mouse-goto-error) map) "Local keymap to use in PostScript run mode.") @@ -1092,7 +1092,7 @@ Use line numbers if `ps-run-error-line-numbers' is not nil." ;; -(add-hook 'kill-emacs-hook 'ps-run-cleanup) +(add-hook 'kill-emacs-hook #'ps-run-cleanup) (provide 'ps-mode)