Package: emacs;
Reported by: Philip Kaludercic <philipk <at> posteo.net>
Date: Mon, 7 Mar 2022 22:34:02 UTC
Severity: normal
Tags: patch
Done: Philip Kaludercic <philipk <at> posteo.net>
Bug is archived. No further changes may be made.
Message #14 received at 54296 <at> debbugs.gnu.org (full text, mbox):
From: Philip Kaludercic <philipk <at> posteo.net> To: Lars Ingebrigtsen <larsi <at> gnus.org> Cc: 54296 <at> debbugs.gnu.org, martin rudalics <rudalics <at> gmx.at> Subject: Re: bug#54296: Add buffer-matching functionality Date: Thu, 10 Mar 2022 10:05:04 +0000
[Message part 1 (text/plain, inline)]
Lars Ingebrigtsen <larsi <at> gnus.org> writes: > Philip Kaludercic <philipk <at> posteo.net> writes: > >> Either way I would consider these functions useful and would have wanted >> to use them in my own code many times before. While difficult, it might >> also be useful for things like display-buffer-alist (the issue is that >> a function as a condition in display-buffer-alist has to accept two >> arguments, while the proposed patch only takes one). > > Hm... how would this be used with display-buffer-alist, then? (And > perhaps Martin has some comments; added to the CCs.) See below. >> To match functions such as string-match, the argument of buffer-match >> could be reversed so that the function can be used as a testfn to >> assoc/alist-get. > > I think I'd prefer to have the parameters reversed -- the condition is a > kind of predicate, and these days we seem to prefer to have the > predicate first. I agree, it makes more sense. >> +(defun buffer-match (buffer condition) >> + "Return non-nil if BUFFER matches CONDITION. >> +CONDITION is is either: >> +- a regular expression, to match a buffer name, >> +- a predicate function that takes a buffer object as argument >> + and returns non-nil if the buffer should be killed, > > Killed? That was a typo from copying the docstring. Here is the updated patch:
[0001-Generalise-buffer-matching-from-project.el.patch (text/x-patch, inline)]
From 6714a4dc7168e6806dba0707c9c0b80d3365b2c5 Mon Sep 17 00:00:00 2001 From: Philip Kaludercic <philipk <at> posteo.net> Date: Mon, 7 Mar 2022 20:49:42 +0100 Subject: [PATCH 1/2] Generalise buffer matching from project.el * subr.el (buffer-match): Add function to check if a buffer satisfies a condition. (match-buffers): Returns all buffers that satisfy a condition. --- lisp/subr.el | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/lisp/subr.el b/lisp/subr.el index 2321765f95..adcd25ec14 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -6613,4 +6613,68 @@ delete-line (forward-line 1) (point)))) +(defun buffer-match (condition buffer-or-name &optional arg) + "Return non-nil if BUFFER-OR-NAME matches CONDITION. +CONDITION is is either: +- a regular expression, to match a buffer name, +- a predicate function that takes a buffer object and ARG as + arguments and returns non-nil if the buffer matches, +- a cons-cell, where the car describes how to interpret the cdr. + The car can be one of the following: + * `major-mode': the buffer matches if the buffer's major + mode is eq to the cons-cell's cdr + * `derived-mode': the buffer matches if the buffer's major + mode is derived from the major mode denoted by the cons-cell's + cdr + * `not': the cdr is interpreted as a negation of a condition. + * `and': the cdr is a list of recursive condition, that all have + to be met. + * `or': the cdr is a list of recursive condition, of which at + least one has to be met." + (letrec + ((buffer (get-buffer buffer-or-name)) + (match + (lambda (conditions) + (catch 'match + (dolist (condition conditions) + (when (cond + ((stringp condition) + (string-match-p condition (buffer-name buffer))) + ((functionp condition) + (if (eq 1 (cdr (func-arity condition))) + (funcall condition buffer) + (funcall condition buffer arg))) + ((eq (car-safe condition) 'major-mode) + (eq (buffer-local-value 'major-mode buffer) + (cdr condition))) + ((eq (car-safe condition) 'derived-mode) + (provided-mode-derived-p + (buffer-local-value 'major-mode buffer) + (cdr condition))) + ((eq (car-safe condition) 'not) + (not (funcall match (cdr condition)))) + ((eq (car-safe condition) 'or) + (funcall match (cdr condition))) + ((eq (car-safe condition) 'and) + (catch 'fail + (dolist (c conditions) + (unless (funcall match c) + (throw 'fail nil))) + t))) + (throw 'match t))))))) + (funcall match (list condition)))) + +(defun match-buffers (condition &optional buffers arg) + "Return a list of buffers that match CONDITION. +See `buffer-match' for details on CONDITION. By default all +buffers are checked, this can be restricted by passing an +optional argument BUFFERS, set to a list of buffers to check. +ARG is passed to `buffer-match', for predicate conditions in +CONDITION." + (let (bufs) + (dolist (buf (or buffers (buffer-list))) + (when (buffer-match condition (get-buffer buf) arg) + (push buf bufs))) + bufs)) + ;;; subr.el ends here -- 2.34.0
[Message part 3 (text/plain, inline)]
martin rudalics <rudalics <at> gmx.at> writes: >>> Either way I would consider these functions useful and would have >>> wanted >>> to use them in my own code many times before. While difficult, it >>> might >>> also be useful for things like display-buffer-alist (the issue is that >>> a function as a condition in display-buffer-alist has to accept two >>> arguments, while the proposed patch only takes one). >> >> Hm... how would this be used with display-buffer-alist, then? (And >> perhaps Martin has some comments; added to the CCs.) > > Either add an optional second argument to 'buffer-match' or add to > 'display-buffer-alist' an entry that uses a function as condition that > calls 'buffer-match' with the first argument and returns non-nil if > 'buffer-match' reports a match. I see no issue here. This seems to work, and updating window.el was also pretty trivial (unless I have missed something):
[0002-window.el-display-buffer-assq-regexp-Use-buffer-matc.patch (text/x-patch, inline)]
From fadea32d0dc74952ca70f8d98ced59616c0e3e1a Mon Sep 17 00:00:00 2001 From: Philip Kaludercic <philipk <at> posteo.net> Date: Thu, 10 Mar 2022 10:59:52 +0100 Subject: [PATCH 2/2] * window.el (display-buffer-assq-regexp): Use buffer-match --- lisp/window.el | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lisp/window.el b/lisp/window.el index 54c9eee5f3..4225019920 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -7497,19 +7497,12 @@ display-buffer-fallback-action (defun display-buffer-assq-regexp (buffer-name alist action) "Retrieve ALIST entry corresponding to BUFFER-NAME. This returns the cdr of the alist entry ALIST if either its key -is a string that matches BUFFER-NAME, as reported by -`string-match-p'; or if the key is a function that returns -non-nil when called with three arguments: the ALIST key, -BUFFER-NAME and ACTION. ACTION should have the form of the -action argument passed to `display-buffer'." +satisfied a BUFFER-NAME per `buffer-match'. ACTION should have +the form of the action argument passed to `display-buffer'." (catch 'match (dolist (entry alist) - (let ((key (car entry))) - (when (or (and (stringp key) - (string-match-p key buffer-name)) - (and (functionp key) - (funcall key buffer-name action))) - (throw 'match (cdr entry))))))) + (when (buffer-match (car entry) buffer-name action) + (throw 'match (cdr entry)))))) (defvar display-buffer--same-window-action '(display-buffer-same-window -- 2.34.0
[Message part 5 (text/plain, inline)]
> martin > -- Philip Kaludercic
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.