From f925fc93bac41d7622d1af927e33b0e738ff55b0 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 16 Mar 2015 14:49:01 -0400 Subject: [PATCH] Add `predicate' arg to `read-buffer' and use it for erc-iswitchb Fixes: debbugs:20116 * src/minibuf.c (Fread_buffer): Add `predicate' argument. * src/callint.c (Fcall_interactively): Adjust calls accordingly. * lisp/erc/erc.el (erc-switch-to-buffer): Rename from erc-iswitchb and rewrite using read-buffer. (erc--buffer-p): New function, extracted from erc-buffer-filter. (erc-buffer-filter): Use it. (erc-with-all-buffers-of-server): Silence compile warning if the return value is unused. (erc-is-valid-nick-p, erc-common-server-suffixes, erc-get-arglist) (erc-command-name, erc-popup-input-buffer): Use \` and \' to match beg/end of string. * lisp/obsolete/iswitchb.el (iswitchb-read-buffer): Add `predicate' arg. * lisp/isearchb.el (isearchb-iswitchb): Adjust accordingly. * lisp/ido.el (ido-read-buffer): Add `predicate' argument. * lisp/misearch.el (unload-function-defs-list): Declare before use. --- etc/NEWS | 4 ++ lisp/ChangeLog | 7 +++ lisp/emulation/viper-init.el | 2 +- lisp/erc/ChangeLog | 12 +++++ lisp/erc/erc.el | 99 +++++++++++++++++------------------- lisp/ido.el | 8 +-- lisp/isearchb.el | 6 ++- lisp/misearch.el | 4 +- lisp/obsolete/iswitchb.el | 6 +-- lisp/replace.el | 2 +- src/ChangeLog | 5 ++ src/callint.c | 4 +- src/minibuf.c | 18 +++++-- 13 files changed, 105 insertions(+), 72 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 24ed0799b2c..cabd0087d92 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -594,6 +594,8 @@ a typographically-correct documents. * Incompatible Lisp Changes in Emacs 25.1 +** read-buffer-function can now be called with a 4th argument (`predicate'). + ** completion-table-dynamic stays in the minibuffer. If you want the old behavior of calling the function in the buffer from which the minibuffer was entered, call it with the new argument @@ -631,6 +633,8 @@ word syntax, use `\sw' instead. * Lisp Changes in Emacs 25.1 +** `read-buffer' takes a new `predicate' argument. + ** Emacs Lisp now supports generators. ** New finalizer facility for running code when objects diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1383fdb2ecf..e9e910a8857 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2015-03-16 Stefan Monnier + + * obsolete/iswitchb.el (iswitchb-read-buffer): Add `predicate' arg. + * isearchb.el (isearchb-iswitchb): Adjust accordingly. + * ido.el (ido-read-buffer): Add `predicate' argument. + * misearch.el (unload-function-defs-list): Declare before use. + 2015-03-16 Vibhav Pant * net/browse-url.el (browse-url-browser-function): Add "Conkeror". diff --git a/lisp/emulation/viper-init.el b/lisp/emulation/viper-init.el index 75932a80d44..e575eee6c93 100644 --- a/lisp/emulation/viper-init.el +++ b/lisp/emulation/viper-init.el @@ -463,7 +463,7 @@ color displays. By default, the delimiters are used only on TTYs." :type 'boolean :group 'viper) -(defcustom viper-read-buffer-function 'read-buffer +(defcustom viper-read-buffer-function #'read-buffer "Function to use for prompting the user for a buffer name." :type 'symbol :group 'viper) diff --git a/lisp/erc/ChangeLog b/lisp/erc/ChangeLog index 4f5fced1bd5..e75b8cc0078 100644 --- a/lisp/erc/ChangeLog +++ b/lisp/erc/ChangeLog @@ -1,3 +1,15 @@ +2015-03-16 Stefan Monnier + + * erc.el (erc-switch-to-buffer): Rename from erc-iswitchb and rewrite + using read-buffer (bug#20116). + (erc--buffer-p): New function, extracted from erc-buffer-filter. + (erc-buffer-filter): Use it. + (erc-with-all-buffers-of-server): Silence compile warning if the return + value is unused. + (erc-is-valid-nick-p, erc-common-server-suffixes, erc-get-arglist) + (erc-command-name, erc-popup-input-buffer): Use \` and \' to match + beg/end of string. + 2015-03-03 Kelvin White * erc.el: Add old version string back to file header for diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a84f9f07523..7e76a6def42 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1110,7 +1110,7 @@ which the local user typed." (define-key map "\C-a" 'erc-bol) (define-key map [home] 'erc-bol) (define-key map "\C-c\C-a" 'erc-bol) - (define-key map "\C-c\C-b" 'erc-iswitchb) + (define-key map "\C-c\C-b" 'erc-switch-to-buffer) (define-key map "\C-c\C-c" 'erc-toggle-interpret-controls) (define-key map "\C-c\C-d" 'erc-input-action) (define-key map "\C-c\C-e" 'erc-toggle-ctcp-autoresponse) @@ -1647,6 +1647,14 @@ If PROC is not supplied, all processes are searched." (throw 'buffer (current-buffer))))) proc)))) +(defun erc--buffer-p (buf predicate proc) + (with-current-buffer buf + (and (derived-mode-p 'erc-mode) + (or (not proc) + (eq proc erc-server-process)) + (funcall predicate) + buf))) + (defun erc-buffer-filter (predicate &optional proc) "Return a list of `erc-mode' buffers matching certain criteria. PREDICATE is a function executed with each buffer, if it returns t, that buffer @@ -1659,12 +1667,7 @@ server connection, or nil which means all open connections." nil (mapcar (lambda (buf) (when (buffer-live-p buf) - (with-current-buffer buf - (and (eq major-mode 'erc-mode) - (or (not proc) - (eq proc erc-server-process)) - (funcall predicate) - buf)))) + (erc--buffer-p buf predicate proc))) (buffer-list))))) (defun erc-buffer-list (&optional predicate proc) @@ -1695,42 +1698,32 @@ nil." ,pro)))) ;; Silence the byte-compiler by binding the result of mapcar to ;; a variable. + (ignore res) res))) -;; (iswitchb-mode) will autoload iswitchb.el -(defvar iswitchb-temp-buflist) -(declare-function iswitchb-read-buffer "iswitchb" - (prompt &optional default require-match start matches-set)) -(defvar iswitchb-make-buflist-hook) - -(defun erc-iswitchb (&optional arg) - "Use `iswitchb-read-buffer' to prompt for a ERC buffer to switch to. +(define-obsolete-function-alias 'erc-iswitchb 'erc-switch-to-buffer "25.1") +(defun erc-switch-to-buffer (&optional arg) + "Prompt for a ERC buffer to switch to. When invoked with prefix argument, use all erc buffers. Without prefix ARG, allow only buffers related to same session server. If `erc-track-mode' is in enabled, put the last element of -`erc-modified-channels-alist' in front of the buffer list. - -Due to some yet unresolved reason, global function `iswitchb-mode' -needs to be active for this function to work." +`erc-modified-channels-alist' in front of the buffer list." (interactive "P") - (let ((enabled (bound-and-true-p iswitchb-mode))) - (or enabled (iswitchb-mode 1)) - (unwind-protect - (let ((iswitchb-make-buflist-hook - (lambda () - (setq iswitchb-temp-buflist - (mapcar 'buffer-name - (erc-buffer-list - nil - (when arg erc-server-process))))))) - (switch-to-buffer - (iswitchb-read-buffer - "Switch-to: " - (if (boundp 'erc-modified-channels-alist) - (buffer-name (caar (last erc-modified-channels-alist))) - nil) - t))) - (or enabled (iswitchb-mode -1))))) + (switch-to-buffer + (read-buffer "Switch to ERC buffer: " + (when (boundp 'erc-modified-channels-alist) + (buffer-name (caar (last erc-modified-channels-alist)))) + t + ;; Only allow ERC buffers in the same session. + (let ((proc (unless arg erc-server-process))) + (lambda (bufname) + (let ((buf (get-buffer bufname))) + (when buf + (erc--buffer-p buf (lambda () t) proc) + (with-current-buffer buf + (and (derived-mode-p 'erc-mode) + (or (null proc) + (eq proc erc-server-process))))))))))) (defun erc-channel-list (proc) "Return a list of channel buffers. @@ -2189,7 +2182,7 @@ be invoked for the values of the other parameters." Arguments are the same as for `erc'." (interactive (erc-select-read-args)) (let ((erc-server-connect-function 'erc-open-tls-stream)) - (apply 'erc r))) + (apply #'erc r))) (defun erc-open-tls-stream (name buffer host port) "Open an TLS stream to an IRC server. @@ -2403,7 +2396,7 @@ If STRING is nil, the function does nothing." (defun erc-is-valid-nick-p (nick) "Check if NICK is a valid IRC nickname." - (string-match (concat "^" erc-valid-nick-regexp "$") nick)) + (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick)) (defun erc-display-line (string &optional buffer) "Display STRING in the ERC BUFFER. @@ -2602,9 +2595,9 @@ server within `erc-lurker-threshold-time'. See also erc-lurker-threshold-time)))) (defcustom erc-common-server-suffixes - '(("openprojects.net$" . "OPN") - ("freenode.net$" . "freenode") - ("oftc.net$" . "OFTC")) + '(("openprojects.net\\'" . "OPN") + ("freenode.net\\'" . "freenode") + ("oftc.net\\'" . "OFTC")) "Alist of common server name suffixes. This variable is used in mode-line display to save screen real estate. Set it to nil if you want to avoid changing @@ -2640,7 +2633,7 @@ ARGS, PARSED, and TYPE are used to format MSG sensibly. See also `erc-format-message' and `erc-display-line'." (let ((string (if (symbolp msg) - (apply 'erc-format-message msg args) + (apply #'erc-format-message msg args) msg))) (setq string (cond @@ -2689,7 +2682,7 @@ See also `erc-server-send'." (defun erc-get-arglist (fun) "Return the argument list of a function without the parens." (let ((arglist (format "%S" (erc-function-arglist fun)))) - (if (string-match "^(\\(.*\\))$" arglist) + (if (string-match "\\`(\\(.*\\))\\'" arglist) (match-string 1 arglist) arglist))) @@ -2705,7 +2698,7 @@ is not alive, nil otherwise." "For CMD being the function name of a ERC command, something like erc-cmd-FOO, this returns a string /FOO." (let ((command-name (symbol-name cmd))) - (if (string-match "^erc-cmd-\\(.*\\)$" command-name) + (if (string-match "\\`erc-cmd-\\(.*\\)\\'" command-name) (concat "/" (match-string 1 command-name)) command-name))) @@ -2796,7 +2789,7 @@ VALUE is computed by evaluating the rest of LINE in Lisp." (erc-display-line (concat "Available user variables:\n" (apply - 'concat + #'concat (mapcar (lambda (var) (let ((val (symbol-value var))) @@ -3775,7 +3768,7 @@ Unban all currently banned users in the current channel." t))) (erc-server-send (format "MODE %s b" chnl))))) - (t (let ((bans (mapcar 'cdr erc-channel-banlist))) + (t (let ((bans (mapcar #'cdr erc-channel-banlist))) (when bans ;; Glob the bans into groups of three, and carry out the unban. ;; eg. /mode #foo -bbb a*!*@* b*!*@* c*!*@* @@ -3930,7 +3923,7 @@ If `point' is at the beginning of a channel name, use that as default." (concat "Set topic of " (erc-default-target) ": ") (when erc-channel-topic (let ((ss (split-string erc-channel-topic "\C-o"))) - (cons (apply 'concat (if (cdr ss) (butlast ss) ss)) + (cons (apply #'concat (if (cdr ss) (butlast ss) ss)) 0)))))) (let ((topic-list (split-string topic "\C-o"))) ; strip off the topic setter (erc-cmd-TOPIC (concat (erc-default-target) " " (car topic-list))))) @@ -5052,7 +5045,7 @@ arg-modes is a list of triples of the form: (MODE-CHAR ON/OFF ARGUMENT)." (if (string-match "^\\s-*\\(\\S-+\\)\\(\\s-.*$\\|$\\)" mode-string) - (let ((chars (mapcar 'char-to-string (match-string 1 mode-string))) + (let ((chars (mapcar #'char-to-string (match-string 1 mode-string))) ;; arguments in channel modes (args-str (match-string 2 mode-string)) (args nil) @@ -5998,7 +5991,7 @@ Returns a list of the form (HIGH LOW), compatible with Emacs time format." (if (> minutes 0) `("%d minutes, %d seconds" ,minutes ,seconds) `("%d seconds" ,seconds)))) - output (apply 'format format-args)) + output (apply #'format format-args)) ;; Change all "1 units" to "1 unit". (while (string-match "\\([^0-9]\\|^\\)1 \\S-+\\(s\\)" output) (setq output (erc-replace-match-subexpression-in-string @@ -6246,7 +6239,7 @@ if `erc-away' is non-nil." (defun erc-format-channel-modes () "Return the current channel's modes." - (concat (apply 'concat + (concat (apply #'concat "+" erc-channel-modes) (cond ((and erc-channel-user-limit erc-channel-key) (if erc-show-channel-key-p @@ -6438,7 +6431,7 @@ All windows are opened in the current frame." "Mode: " (mapcar (lambda (e) (list (symbol-name e))) - (apropos-internal "-mode$" 'commandp)) + (apropos-internal "-mode\\'" 'commandp)) nil t)))) (pop-to-buffer (make-indirect-buffer (current-buffer) buffer-name)) (funcall mode) @@ -6634,7 +6627,7 @@ See also `format-spec'." (error "No format spec for message %s" msg)) (when (functionp entry) (setq entry (apply entry args))) - (format-spec entry (apply 'format-spec-make args)))) + (format-spec entry (apply #'format-spec-make args)))) ;;; Various hook functions diff --git a/lisp/ido.el b/lisp/ido.el index 563f406aeb6..60a59d6e99d 100644 --- a/lisp/ido.el +++ b/lisp/ido.el @@ -1590,10 +1590,10 @@ enable the mode if ARG is omitted or nil." (when ido-everywhere (when (memq ido-mode '(both file)) (put 'ido-everywhere 'file (cons read-file-name-function nil)) - (setq read-file-name-function 'ido-read-file-name)) + (setq read-file-name-function #'ido-read-file-name)) (when (memq ido-mode '(both buffer)) (put 'ido-everywhere 'buffer (cons read-buffer-function nil)) - (setq read-buffer-function 'ido-read-buffer)))) + (setq read-buffer-function #'ido-read-buffer)))) (defvar ido-minor-mode-map-entry nil) @@ -4782,7 +4782,7 @@ Modified from `icomplete-completions'." (put 'dired-do-rename 'ido 'ignore) ;;;###autoload -(defun ido-read-buffer (prompt &optional default require-match) +(defun ido-read-buffer (prompt &optional default require-match predicate) "Ido replacement for the built-in `read-buffer'. Return the name of a buffer selected. PROMPT is the prompt to give to the user. DEFAULT if given is the default @@ -4796,7 +4796,7 @@ If REQUIRE-MATCH is non-nil, an existing buffer must be selected." (if (eq ido-exit 'fallback) (let ((read-buffer-function nil)) (run-hook-with-args 'ido-before-fallback-functions 'read-buffer) - (read-buffer prompt default require-match)) + (read-buffer prompt default require-match predicate)) buf))) ;;;###autoload diff --git a/lisp/isearchb.el b/lisp/isearchb.el index ffd4d62be38..5e7771cea52 100644 --- a/lisp/isearchb.el +++ b/lisp/isearchb.el @@ -75,7 +75,9 @@ ;; killing iswitchb.el and then trying to switch back is broken ;; make sure TAB isn't broken -(require 'iswitchb) +;;; Code: + +(require 'iswitchb) ;FIXME: Don't rely on iswitchb! (defgroup isearchb nil "Switch between buffers using a mechanism like isearch." @@ -118,7 +120,7 @@ Its purpose is to pass different call arguments to (interactive) (let* ((prompt "iswitch ") (iswitchb-method 'samewindow) - (buf (iswitchb-read-buffer prompt nil nil iswitchb-text t))) + (buf (iswitchb-read-buffer prompt nil nil nil iswitchb-text t))) (if (eq iswitchb-exit 'findfile) (call-interactively 'find-file) (when buf diff --git a/lisp/misearch.el b/lisp/misearch.el index dcc819564fb..65969113d93 100644 --- a/lisp/misearch.el +++ b/lisp/misearch.el @@ -234,7 +234,7 @@ set in `multi-isearch-buffers' or `multi-isearch-buffers-regexp'." (ido-ignore-item-temp-list bufs)) (while (not (string-equal (setq buf (read-buffer - (if (eq read-buffer-function 'ido-read-buffer) + (if (eq read-buffer-function #'ido-read-buffer) "Next buffer to search (C-j to end): " "Next buffer to search (RET to end): ") nil t)) @@ -377,6 +377,8 @@ whose file names match the specified wildcard." (goto-char (if isearch-forward (point-min) (point-max))) (isearch-forward-regexp nil t))) +(defvar unload-function-defs-list) + (defun multi-isearch-unload-function () "Remove autoloaded variables from `unload-function-defs-list'. Also prevent the feature from being reloaded via `isearch-mode-hook'." diff --git a/lisp/obsolete/iswitchb.el b/lisp/obsolete/iswitchb.el index 6b1e5347e21..111de8537d3 100644 --- a/lisp/obsolete/iswitchb.el +++ b/lisp/obsolete/iswitchb.el @@ -175,10 +175,10 @@ ;; iswitchb-read-buffer has been written to be a drop in replacement ;; for the normal buffer selection routine `read-buffer'. To use ;; iswitch for all buffer selections in Emacs, add: -;; (setq read-buffer-function 'iswitchb-read-buffer) +;; (setq read-buffer-function #'iswitchb-read-buffer) ;; (This variable was introduced in Emacs 20.3.) ;; XEmacs users can get the same behavior by doing: -;; (defalias 'read-buffer 'iswitchb-read-buffer) +;; (defalias 'read-buffer #'iswitchb-read-buffer) ;; since `read-buffer' is defined in lisp. ;; Using iswitchb for other completion tasks. @@ -586,7 +586,7 @@ in a separate window. )))) (defun iswitchb-read-buffer (prompt &optional default require-match - start matches-set) + _predicate start matches-set) "Replacement for the built-in `read-buffer'. Return the name of a buffer selected. PROMPT is the prompt to give to the user. diff --git a/lisp/replace.el b/lisp/replace.el index e0636e0728c..70b86dd2016 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1369,7 +1369,7 @@ See also `multi-occur-in-matching-buffers'." (ido-ignore-item-temp-list bufs)) (while (not (string-equal (setq buf (read-buffer - (if (eq read-buffer-function 'ido-read-buffer) + (if (eq read-buffer-function #'ido-read-buffer) "Next buffer to search (C-j to end): " "Next buffer to search (RET to end): ") nil t)) diff --git a/src/ChangeLog b/src/ChangeLog index e328afcde8f..fbf8fb452fc 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2015-03-16 Stefan Monnier + + * minibuf.c (Fread_buffer): Add `predicate' argument. + * callint.c (Fcall_interactively): Adjust calls accordingly. + 2015-03-15 Eli Zaretskii * xdisp.c (handle_invisible_prop): Fix up it->position even when diff --git a/src/callint.c b/src/callint.c index 0c6c03036c8..cf50e0c3788 100644 --- a/src/callint.c +++ b/src/callint.c @@ -531,13 +531,13 @@ invoke it. If KEYS is omitted or nil, the return value of args[i] = Fcurrent_buffer (); if (EQ (selected_window, minibuf_window)) args[i] = Fother_buffer (args[i], Qnil, Qnil); - args[i] = Fread_buffer (callint_message, args[i], Qt); + args[i] = Fread_buffer (callint_message, args[i], Qt, Qnil); break; case 'B': /* Name of buffer, possibly nonexistent. */ args[i] = Fread_buffer (callint_message, Fother_buffer (Fcurrent_buffer (), Qnil, Qnil), - Qnil); + Qnil, Qnil); break; case 'c': /* Character. */ diff --git a/src/minibuf.c b/src/minibuf.c index e7c288b251b..c03316965d3 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -1081,7 +1081,7 @@ A user option, or customizable variable, is one for which return Fintern (name, Qnil); } -DEFUN ("read-buffer", Fread_buffer, Sread_buffer, 1, 3, 0, +DEFUN ("read-buffer", Fread_buffer, Sread_buffer, 1, 4, 0, doc: /* Read the name of a buffer and return as a string. Prompt with PROMPT. Optional second arg DEF is value to return if user enters an empty line. @@ -1093,8 +1093,11 @@ The argument PROMPT should be a string ending with a colon and a space. If `read-buffer-completion-ignore-case' is non-nil, completion ignores case while reading the buffer name. If `read-buffer-function' is non-nil, this works by calling it as a -function, instead of the usual behavior. */) - (Lisp_Object prompt, Lisp_Object def, Lisp_Object require_match) +function, instead of the usual behavior. +Optional arg PREDICATE if non-nil is a function limiting the buffers that can +be considered. */) + (Lisp_Object prompt, Lisp_Object def, Lisp_Object require_match, + Lisp_Object predicate) { Lisp_Object result; char *s; @@ -1136,11 +1139,16 @@ function, instead of the usual behavior. */) } result = Fcompleting_read (prompt, intern ("internal-complete-buffer"), - Qnil, require_match, Qnil, + predicate, require_match, Qnil, Qbuffer_name_history, def, Qnil); } else - result = call3 (Vread_buffer_function, prompt, def, require_match); + result = (NILP (predicate) + /* Partial backward compatibility for older read_buffer_functions + which don't expect a `predicate' argument. */ + ? call3 (Vread_buffer_function, prompt, def, require_match) + : call4 (Vread_buffer_function, prompt, def, require_match, + predicate)); return unbind_to (count, result); } -- 2.39.2