From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Christopher Genovese Newsgroups: gmane.emacs.devel Subject: Re: Ibuffer improvements: filtering, documentation, bug fix, tests Date: Wed, 14 Dec 2016 14:47:42 -0500 Message-ID: References: <877f7zhg79.fsf@gmail.com> <87twamnx3f.fsf@gmail.com> <87r35hor1o.fsf@gmail.com> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=94eb2c088ee26e61870543a39d65 X-Trace: blaine.gmane.org 1481745050 27303 195.159.176.226 (14 Dec 2016 19:50:50 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 14 Dec 2016 19:50:50 +0000 (UTC) Cc: emacs-devel To: Tino Calancha Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Dec 14 20:50:39 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cHFZV-0005QJ-O6 for ged-emacs-devel@m.gmane.org; Wed, 14 Dec 2016 20:50:38 +0100 Original-Received: from localhost ([::1]:49827 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cHFZa-000153-1o for ged-emacs-devel@m.gmane.org; Wed, 14 Dec 2016 14:50:42 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40833) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cHFYb-0000Oj-9U for emacs-devel@gnu.org; Wed, 14 Dec 2016 14:49:54 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cHFYO-0003ov-4W for emacs-devel@gnu.org; Wed, 14 Dec 2016 14:49:41 -0500 Original-Received: from mail-it0-f54.google.com ([209.85.214.54]:36169) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cHFYN-0003iG-Fx for emacs-devel@gnu.org; Wed, 14 Dec 2016 14:49:28 -0500 Original-Received: by mail-it0-f54.google.com with SMTP id l8so8673071iti.1 for ; Wed, 14 Dec 2016 11:49:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=ICOJIQW9jo57a4G6qEitcmmKWXKJfgK7Tg+j8Z43WWM=; b=e81rqE+kC6rydCDlKZsmEC83NINoJBqlS25B717qjL4LqHtvigFYz2WnjhJsbuT1A2 MLQZ1L8mZ40nMqWnuoFHIC0zb+XiSrQQ+RN8ihs1oIAlQ0WG7cd1ulBYHSqgqI5H2Gvp d0nPqq+dq/MUYJoQQkF7xDJ770NbgP/zL30FkT0/77RrfCsalGLee7I0TDd/rT6IB01z 3KDrj13w+RU3YwnBnkTTIIgelrXV2I5xyLa8CRYO4nrV//MgiV3CMpQuA31as4l8HpZN AGcCRN6lyb1QoVivBxc0f14dJ5KogMKteNstd8iFLThfNBpB5lsyu3xZiYz6MjsykHlw u+Mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=ICOJIQW9jo57a4G6qEitcmmKWXKJfgK7Tg+j8Z43WWM=; b=EqZFFriLzqOSxyQmRq8GKULhmTevukh1L85eZwVf2J81vrCjQIQyruzM0r5jRfZAku nxHaAEFw1BZGFziziuWJK9j09K8HGNAnJv8SPhZRVeymxxFgS+4dvoECeagoMEhTL1N2 GCJ9lsJZR7KLfgF6ZXndEhNdD/7R5pXzg3wChNLjDtFSgnn9NadMUTht0s6UbtpvFBOu 8Qc7aJQvWv0+/4zuo7uHIRZn+9Xnj4rwbUSD8nQ0D5/kXKlp87/T/UWV4f7n2eUj+9cl MSgOGo0L95dSbPDphxaMkSJHf3s7j990mfDSATzujf40nKD5fsQzkqIMuTmB+7FdZSOw zD1Q== X-Gm-Message-State: AKaTC01oQPZBc6qaV8mEux3LhUXMsPMXXmesUm5C2HN8YXLTmh45Ygn1C+VEjCvbsiSJocfOxnTt5ZQrFMeAYQ== X-Received: by 10.36.130.66 with SMTP id t63mr9437525itd.90.1481744883538; Wed, 14 Dec 2016 11:48:03 -0800 (PST) Original-Received: by 10.107.59.143 with HTTP; Wed, 14 Dec 2016 11:47:42 -0800 (PST) In-Reply-To: <87r35hor1o.fsf@gmail.com> X-Google-Sender-Auth: VZtg_MCL7avyuywZdrKDApTbwxY X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.214.54 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:210466 Archived-At: --94eb2c088ee26e61870543a39d65 Content-Type: text/plain; charset=UTF-8 Tino, I just had a chance to apply the patch, rebuild, and test. Two things: 1. The "(ignore qualifier)" statement you added to several of the filters causes the filters to always return nil. Removing this ignore fixes the problem and makes the tests pass. But I think this is actually a new problem that was introduced in more recent changes to ibuf-macs.el. What seems to be happening on first look is that the filter code in define-ibuffer-filter is now wrapped in a condition-case inside a lambda making the ignore form the body form and thus always giving a nil result. In the versions when we started this, the filter function was directly wrapped in a lambda so the ignore directive you included could take effect. Looking in the current version of ibuf-macs.el for the definition of define-ibuffer-filter it has (condition-case nil ,@body (error (ibuffer-pop-filter) ...)) but I think this should have the spliced ,@body wrapped in a progn. That would also solve the problem. Whether the ignore would suppress the compiler warnings in that position as you intended, I'm not sure. 2. This patch removed the additional default saved filters that I had added ("TeX", "text document", "web"), which is fine. But one of my tests used one of those saved filters because I had it predefined in ibuffer-saved-filters. It's an easy change either way to fix this. All the other tests pass without a problem. Let me know how you'd like me to proceed. -- Chris On Thu, Dec 8, 2016 at 8:00 PM, Tino Calancha wrote: > Tino Calancha writes: > > > Christopher Genovese writes: > > > >> Tino, > >> > >> Sorry it took so long to get this to you; it's been a crazy week. > >> I've attached a patch file with all the changes we have discussed > >> (except one, see below) to the code, change logs, and NEWS > > Without the fix to Bug#25049 is easier to review. Thank you! > > You made a great job and very fast! > > > > I have divided the patch in two parts. > > Hi Chris, > > This week ibuffer.el and ibuf-ext.el have changed significatly > for bug fixing. I have updated your patch in this thread to > be applied on top of the current master branch. > > Let's test a few days more this updated patch to confirm that > everything works as expected. > > The updated patch can be applied to the current state of the > master branch, i.e., currently the commit > f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1 > > Regards, > Tino > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > ;;;;;;;;;;;;;;;;;;; > From 1cffd494f352c8b990d36e99cebd8f70e746d6c4 Mon Sep 17 00:00:00 2001 > From: Christopher Genovese > Date: Fri, 9 Dec 2016 09:13:06 +0900 > Subject: [PATCH 1/2] ibuffer: New filters and commands > > Add several new filters and improve documentation. > See discussion on: > https://lists.gnu.org/archive/html/emacs-devel/2016-11/msg00399.html > * lisp/ibuf-ext.el: Add paragraph to file commentary. > (ibuffer-saved-filters, ibuffer-filtering-qualifiers) > (ibuffer-filter-groups): Update doc string. > (ibuffer-unary-operand): Add new function that transparently > handles 'not' formats for compound filters. > (ibuffer-included-in-filter-p): Handle 'not' fully; update doc string. > (ibuffer-included-in-filter-p-1): Handle 'and' compound filters. > (ibuffer-decompose-filter): Handle 'and' as well, > and handle 'not' consistently with other uses. > (ibuffer-and-filter): New defun analogous to 'ibuffer-or-filter'. > (ibuffer--or-and-filter): New defun. > (ibuffer-or-filter, ibuffer-and-filter): Use it. > (ibuffer-format-qualifier): Handle 'and' filters as well. > (ibuffer-filter-by-basename, ibuffer-filter-by-file-extension) > (ibuffer-filter-by-directory, ibuffer-filter-by-starred-name) > (ibuffer-filter-by-modified, ibuffer-filter-by-visiting-file): > Add new pre-defined filters. > (ibuffer-filter-chosen-by-completion): Add new interactive command > for easily choosing a filter from the descriptions. > * lisp/ibuffer.el (ibuffer-mode-map): > Bind ibuffer-filter-by-basename, ibuffer-filter-by-file-extension, > ibuffer-filter-by-starred-name, ibuffer-filter-by-modified, > ibuffer-filter-by-visiting-file to '/b', '/.', '/*', '/i', '/v' > respectively; bind 'ibuffer-or-filter', 'ibuffer-and-filter', > 'ibuffer-pop-filter' ,'ibuffer-pop-filter-group' and > 'ibuffer-filter-disable' to '/|', '/&', '/', '/S-' > and '/ DEL' respectively. > * test/lisp/ibuffer-tests.el (ibuffer-autoload): Add appropriate > skip specification. > Add menu entries for the new filters. > (ibuffer-filter-inclusion-1, ibuffer-filter-inclusion-2 > ibuffer-filter-inclusion-3, ibuffer-filter-inclusion-4 > ibuffer-filter-inclusion-5, ibuffer-filter-inclusion-6 > ibuffer-filter-inclusion-7, ibuffer-filter-inclusion-8 > ibuffer-decompose-filter, ibuffer-and-filter > ibuffer-or-filter): Add new tests; they are skipped unless > ibuf-ext is loaded. > ; * etc/NEWS: Add entries for new user-facing features. > --- > etc/NEWS | 21 ++ > lisp/ibuf-ext.el | 318 ++++++++++++++++----- > lisp/ibuffer.el | 55 +++- > test/lisp/ibuffer-tests.el | 667 ++++++++++++++++++++++++++++++ > ++++++++++++++- > 4 files changed, 989 insertions(+), 72 deletions(-) > > diff --git a/etc/NEWS b/etc/NEWS > index a62668a..f60deb1 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -316,6 +316,27 @@ bound to 'Buffer-menu-unmark-all-buffers'. > ** Ibuffer > > --- > +*** New filter commands `ibuffer-filter-by-basename', > +`ibuffer-filter-by-file-extension', `ibuffer-filter-by-directory', > +`ibuffer-filter-by-starred-name', `ibuffer-filter-by-modified' > +and `ibuffer-filter-by-visiting-file'; bound respectively > +to '/b', '/.', '//', '/*', '/i' and '/v'. > + > +--- > +*** Two new commands 'ibuffer-filter-chosen-by-completion' > +and `ibuffer-and-filter', the second bound to '/&'. > + > +--- > +*** The commands `ibuffer-pop-filter', `ibuffer-pop-filter-group', > +`ibuffer-or-filter' and `ibuffer-filter-disable' have the alternative > +bindings '/', '/S-', '/|' and '/DEL', respectively. > + > +--- > +*** The data format specifying filters has been extended to allow > +explicit logical 'and', and a more flexible form for logical 'not'. > +See 'ibuffer-filtering-qualifiers' doc string for full details. > + > +--- > *** A new command 'ibuffer-copy-buffername-as-kill'; bound > to 'B'. > > diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el > index 9ce7b5a..d1e70b6 100644 > --- a/lisp/ibuf-ext.el > +++ b/lisp/ibuf-ext.el > @@ -28,6 +28,13 @@ > ;; These functions should be automatically loaded when called, but you > ;; can explicitly (require 'ibuf-ext) in your ~/.emacs to have them > ;; preloaded. > +;; > +;; For details on the structure of ibuffer filters and filter groups, > +;; see the documentation for variables `ibuffer-filtering-qualifiers', > +;; `ibuffer-filter-groups', and `ibuffer-saved-filters' in that order. > +;; The variable `ibuffer-filtering-alist' contains names and > +;; descriptions of the currently defined filters; also see the macro > +;; `define-ibuffer-filter'. > > ;;; Code: > > @@ -214,8 +221,48 @@ ibuffer-old-saved-filters-warning > ")) > > (defvar ibuffer-filtering-qualifiers nil > - "A list like (SYMBOL . QUALIFIER) which filters the current buffer list. > -See also `ibuffer-filtering-alist'.") > + "A list specifying the filters currently acting on the buffer list. > + > +If this list is nil, then no filters are currently in > +effect. Otherwise, each element of this list specifies a single > +filter, and all of the specified filters in the list are applied > +successively to the buffer list. > + > +Each filter specification can be of two types: simple or compound. > + > +A simple filter specification has the form (SYMBOL . QUALIFIER), > +where SYMBOL is a key in the alist `ibuffer-filtering-alist' that > +determines the filter function to use and QUALIFIER is the data > +passed to that function (along with the buffer being considered). > + > +A compound filter specification can have one of four forms: > + > +-- (not FILTER-SPEC) > + > + Represents the logical complement of FILTER-SPEC, which > + is any single filter specification, simple or compound. > + The form (not . FILTER-SPEC) is also accepted here. > + > +-- (and FILTER-SPECS...) > + > + Represents the logical-and of the filters defined by one or > + more filter specifications FILTER-SPECS..., where each > + specification can be simple or compound. Note that and is > + implicitly applied to the filters in the top-level list. > + > +-- (or FILTER-SPECS...) > + > + Represents the logical-or of the filters defined by one or > + more filter specifications FILTER-SPECS..., where each > + specification can be simple or compound. > + > +-- (saved . \"NAME\") > + > + Represents the filter saved under the string NAME > + in the alist `ibuffer-saved-filters'. It is an > + error to name a filter that has not been saved. > + > +This variable is local to each ibuffer buffer.") > > ;; This is now frobbed by `define-ibuffer-filter'. > (defvar ibuffer-filtering-alist nil > @@ -247,10 +294,18 @@ ibuffer-cached-filter-formats > (defvar ibuffer-compiled-filter-formats nil) > > (defvar ibuffer-filter-groups nil > - "A list like ((\"NAME\" ((SYMBOL . QUALIFIER) ...) ...) which groups > buffers. > -The SYMBOL should be one from `ibuffer-filtering-alist'. > -The QUALIFIER should be the same as QUALIFIER in > -`ibuffer-filtering-qualifiers'.") > + "An alist giving this buffer's active filter groups, or nil if none. > + > +This alist maps filter group labels to filter specification > +lists. Each element has the form (\"LABEL\" FILTER-SPECS...), > +where FILTER-SPECS... represents one or more filter > +specifications of the same form as allowed as elements of > +`ibuffer-filtering-qualifiers'. > + > +Each filter group is displayed as a separate section in the > +ibuffer list, headed by LABEL and displaying only the buffers > +that pass through all the filters associated with NAME in this > +list.") > > (defcustom ibuffer-show-empty-filter-groups t > "If non-nil, then show the names of filter groups which are empty." > @@ -260,20 +315,21 @@ ibuffer-show-empty-filter-groups > (defcustom ibuffer-saved-filter-groups nil > "An alist of filtering groups to switch between. > > -This variable should look like ((\"STRING\" QUALIFIERS) > - (\"STRING\" QUALIFIERS) ...), where > -QUALIFIERS is a list of the same form as > -`ibuffer-filtering-qualifiers'. > +Each element is of the form (\"NAME\" . FILTER-GROUP-LIST), > +where NAME is a unique but arbitrary name and FILTER-GROUP-LIST > +is a list of filter groups with the same structure as > +allowed for `ibuffer-filter-groups'. > > -See also the variables `ibuffer-filter-groups', > -`ibuffer-filtering-qualifiers', `ibuffer-filtering-alist', and the > -functions `ibuffer-switch-to-saved-filter-groups', > -`ibuffer-save-filter-groups'." > +See also the functions `ibuffer-save-filter-groups' and > +`ibuffer-switch-to-saved-filter-groups' for saving and switching > +between sets of filter groups, and the variable > +`ibuffer-save-with-custom' that affects how this information is > +saved." > :type '(repeat sexp) > :group 'ibuffer) > > (defvar ibuffer-hidden-filter-groups nil > - "A list of filtering groups which are currently hidden.") > + "The list of filter groups that are currently hidden.") > > (defvar ibuffer-filter-group-kill-ring nil) > > @@ -602,18 +658,38 @@ print > > ;;;###autoload > (defun ibuffer-included-in-filters-p (buf filters) > + "Return non-nil if BUF passes all FILTERS. > + > +BUF is a lisp buffer object, and FILTERS is a list of filter > +specifications with the same structure as > +`ibuffer-filtering-qualifiers'." > (not > (memq nil ;; a filter will return nil if it failed > - (mapcar > - ;; filter should be like (TYPE . QUALIFIER), or > - ;; (or (TYPE . QUALIFIER) (TYPE . QUALIFIER) ...) > - #'(lambda (qual) > - (ibuffer-included-in-filter-p buf qual)) > - filters)))) > + (mapcar #'(lambda (filter) > + (ibuffer-included-in-filter-p buf filter)) > + filters)))) > + > +(defun ibuffer-unary-operand (filter) > + "Extracts operand from a unary compound FILTER specification. > + > +FILTER should be a cons cell of either form (f . d) or (f d), > +where operand d is itself a cons cell, or nil. Returns d." > + (let* ((tail (cdr filter)) > + (maybe-q (car-safe tail))) > + (if (consp maybe-q) maybe-q tail))) > > (defun ibuffer-included-in-filter-p (buf filter) > + "Return non-nil if BUF pass FILTER. > + > +BUF is a lisp buffer object, and FILTER is a filter > +specification, with the same structure as an element of the list > +`ibuffer-filtering-qualifiers'." > (if (eq (car filter) 'not) > - (not (ibuffer-included-in-filter-p-1 buf (cdr filter))) > + (let ((inner (ibuffer-unary-operand filter))) > + ;; Allows (not (not ...)) etc, which may be overkill > + (if (eq (car inner) 'not) > + (ibuffer-included-in-filter-p buf (ibuffer-unary-operand > inner)) > + (not (ibuffer-included-in-filter-p-1 buf inner)))) > (ibuffer-included-in-filter-p-1 buf filter))) > > (defun ibuffer-included-in-filter-p-1 (buf filter) > @@ -621,9 +697,19 @@ ibuffer-included-in-filter-p-1 > (not > (pcase (car filter) > (`or > + ;;; ATTN: Short-circuiting alternative with parallel structure > w/`and > + ;;(catch 'has-match > + ;; (dolist (filter-spec (cdr filter) nil) > + ;; (when (ibuffer-included-in-filter-p buf filter-spec) > + ;; (throw 'has-match t)))) > (memq t (mapcar #'(lambda (x) > - (ibuffer-included-in-filter-p buf x)) > - (cdr filter)))) > + (ibuffer-included-in-filter-p buf x)) > + (cdr filter)))) > + (`and > + (catch 'no-match > + (dolist (filter-spec (cdr filter) t) > + (unless (ibuffer-included-in-filter-p buf filter-spec) > + (throw 'no-match nil))))) > (`saved > (let ((data (assoc (cdr filter) ibuffer-saved-filters))) > (unless data > @@ -916,17 +1002,17 @@ ibuffer-pop-filter > (when buf > (ibuffer-jump-to-buffer (buffer-name buf))))) > > -(defun ibuffer-push-filter (qualifier) > - "Add QUALIFIER to `ibuffer-filtering-qualifiers'." > - (push qualifier ibuffer-filtering-qualifiers)) > +(defun ibuffer-push-filter (filter-specification) > + "Add FILTER-SPECIFICATION to `ibuffer-filtering-qualifiers'." > + (push filter-specification ibuffer-filtering-qualifiers)) > > ;;;###autoload > (defun ibuffer-decompose-filter () > - "Separate the top compound filter (OR, NOT, or SAVED) in this buffer. > + "Separate this buffer's top compound filter (AND, OR, NOT, or SAVED). > > This means that the topmost filter on the filtering stack, which must > be a complex filter like (OR [name: foo] [mode: bar-mode]), will be > -turned into two separate filters [name: foo] and [mode: bar-mode]." > +turned into separate filters, like [name: foo] and [mode: bar-mode]." > (interactive) > (unless ibuffer-filtering-qualifiers > (error "No filters in effect")) > @@ -935,14 +1021,14 @@ ibuffer-decompose-filter > (tail (cdr filters)) > (value > (pcase (caar filters) > - (`or (nconc head tail)) > + ((or `or 'and) (nconc head tail)) > (`saved > (let ((data (assoc head ibuffer-saved-filters))) > (unless data > (ibuffer-filter-disable) > (error "Unknown saved filter %s" head)) > (append (cdr data) tail))) > - (`not (cons head tail)) > + (`not (cons (ibuffer-unary-operand (car filters)) tail)) > (_ > (error "Filter type %s is not compound" (caar filters)))))) > (setq ibuffer-filtering-qualifiers value)) > @@ -971,31 +1057,36 @@ ibuffer-negate-filter > ibuffer-filtering-qualifiers)) > (ibuffer-update nil t)) > > +(defun ibuffer--or-and-filter (op decompose) > + (if decompose > + (if (eq op (caar ibuffer-filtering-qualifiers)) > + (ibuffer-decompose-filter) > + (error "Top filter is not an %s" (upcase (symbol-name op)))) > + (when (< (length ibuffer-filtering-qualifiers) 2) > + (error "Need two filters to %s" (upcase (symbol-name op)))) > + ;; If either filter is an op, eliminate unnecessary nesting. > + (let ((first (pop ibuffer-filtering-qualifiers)) > + (second (pop ibuffer-filtering-qualifiers))) > + (push (nconc (if (eq op (car first)) first (list op first)) > + (if (eq op (car second)) (cdr second) (list second))) > + ibuffer-filtering-qualifiers))) > + (ibuffer-update nil t)) > + > ;;;###autoload > -(defun ibuffer-or-filter (&optional reverse) > +(defun ibuffer-or-filter (&optional decompose) > "Replace the top two filters in this buffer with their logical OR. > -If optional argument REVERSE is non-nil, instead break the top OR > +If optional argument DECOMPOSE is non-nil, instead break the top OR > filter into parts." > (interactive "P") > - (if reverse > - (progn > - (when (or (null ibuffer-filtering-qualifiers) > - (not (eq 'or (caar ibuffer-filtering-qualifiers)))) > - (error "Top filter is not an OR")) > - (let ((lim (pop ibuffer-filtering-qualifiers))) > - (setq ibuffer-filtering-qualifiers > - (nconc (cdr lim) ibuffer-filtering-qualifiers)))) > - (when (< (length ibuffer-filtering-qualifiers) 2) > - (error "Need two filters to OR")) > - ;; If the second filter is an OR, just add to it. > - (let ((first (pop ibuffer-filtering-qualifiers)) > - (second (pop ibuffer-filtering-qualifiers))) > - (if (eq 'or (car second)) > - (push (nconc (list 'or first) (cdr second)) > - ibuffer-filtering-qualifiers) > - (push (list 'or first second) > - ibuffer-filtering-qualifiers)))) > - (ibuffer-update nil t)) > + (ibuffer--or-and-filter 'or decompose)) > + > +;;;###autoload > +(defun ibuffer-and-filter (&optional decompose) > + "Replace the top two filters in this buffer with their logical AND. > +If optional argument DECOMPOSE is non-nil, instead break the top AND > +filter into parts." > + (interactive "P") > + (ibuffer--or-and-filter 'and decompose)) > > (defun ibuffer-maybe-save-stuff () > (when ibuffer-save-with-custom > @@ -1069,7 +1160,9 @@ ibuffer-format-filter-group-data > > (defun ibuffer-format-qualifier (qualifier) > (if (eq (car-safe qualifier) 'not) > - (concat " [NOT" (ibuffer-format-qualifier-1 (cdr qualifier)) "]") > + (concat " [NOT" > + (ibuffer-format-qualifier-1 (ibuffer-unary-operand > qualifier)) > + "]") > (ibuffer-format-qualifier-1 qualifier))) > > (defun ibuffer-format-qualifier-1 (qualifier) > @@ -1078,14 +1171,16 @@ ibuffer-format-qualifier-1 > (concat " [filter: " (cdr qualifier) "]")) > (`or > (concat " [OR" (mapconcat #'ibuffer-format-qualifier > - (cdr qualifier) "") "]")) > + (cdr qualifier) "") "]")) > + (`and > + (concat " [AND" (mapconcat #'ibuffer-format-qualifier > + (cdr qualifier) "") "]")) > (_ > (let ((type (assq (car qualifier) ibuffer-filtering-alist))) > (unless qualifier > - (error "Ibuffer: bad qualifier %s" qualifier)) > + (error "Ibuffer: bad qualifier %s" qualifier)) > (concat " [" (cadr type) ": " (format "%s]" (cdr qualifier))))))) > > - > (defun ibuffer-list-buffer-modes (&optional include-parents) > "Create a completion table of buffer modes currently in use. > If INCLUDE-PARENTS is non-nil then include parent modes." > @@ -1103,7 +1198,7 @@ ibuffer-list-buffer-modes > > ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext") > (define-ibuffer-filter mode > - "Toggle current view to buffers with major mode QUALIFIER." > + "Limit current view to buffers with major mode QUALIFIER." > (:description "major mode" > :reader > (let* ((buf (ibuffer-current-buffer)) > @@ -1123,7 +1218,7 @@ mode > > ;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-ext") > (define-ibuffer-filter used-mode > - "Toggle current view to buffers with major mode QUALIFIER. > + "Limit current view to buffers with major mode QUALIFIER. > Called interactively, this function allows selection of modes > currently used by buffers." > (:description "major mode in use" > @@ -1142,7 +1237,7 @@ used-mode > > ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext") > (define-ibuffer-filter derived-mode > - "Toggle current view to buffers whose major mode inherits from > QUALIFIER." > + "Limit current view to buffers whose major mode inherits from > QUALIFIER." > (:description "derived mode" > :reader > (intern > @@ -1153,22 +1248,74 @@ derived-mode > > ;;;###autoload (autoload 'ibuffer-filter-by-name "ibuf-ext") > (define-ibuffer-filter name > - "Toggle current view to buffers with name matching QUALIFIER." > + "Limit current view to buffers with name matching QUALIFIER." > (:description "buffer name" > :reader (read-from-minibuffer "Filter by name (regexp): ")) > (string-match qualifier (buffer-name buf))) > > +;;;###autoload (autoload 'ibuffer-filter-by-starred-name "ibuf-ext") > +(define-ibuffer-filter starred-name > + "Limit current view to buffers with name beginning and ending > +with *, along with an optional suffix of the form digits or > +." > + (:description "starred buffer name" > + :reader nil) > + (ignore qualifier) > + (string-match "\\`\\*[^*]+\\*\\(?:<[[:digit:]]+>\\)?\\'" (buffer-name > buf))) > + > ;;;###autoload (autoload 'ibuffer-filter-by-filename "ibuf-ext") > (define-ibuffer-filter filename > - "Toggle current view to buffers with filename matching QUALIFIER." > - (:description "filename" > - :reader (read-from-minibuffer "Filter by filename (regexp): ")) > + "Limit current view to buffers with full file name matching QUALIFIER. > + > +For example, for a buffer associated with file '/a/b/c.d', this > +matches against '/a/b/c.d'." > + (:description "full file name" > + :reader (read-from-minibuffer "Filter by full file name (regexp): ")) > (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name)) > (string-match qualifier it))) > > +;;;###autoload (autoload 'ibuffer-filter-by-basename "ibuf-ext") > +(define-ibuffer-filter basename > + "Limit current view to buffers with file basename matching QUALIFIER. > + > +For example, for a buffer associated with file '/a/b/c.d', this > +matches against 'c.d'." > + (:description "file basename" > + :reader (read-from-minibuffer > + "Filter by file name, without directory part (regex): ")) > + (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name)) > + (string-match qualifier (file-name-nondirectory it)))) > + > +;;;###autoload (autoload 'ibuffer-filter-by-file-extension "ibuf-ext") > +(define-ibuffer-filter file-extension > + "Limit current view to buffers with filename extension matching > QUALIFIER. > + > +The separator character (typically `.') is not part of the > +pattern. For example, for a buffer associated with file > +'/a/b/c.d', this matches against 'd'." > + (:description "filename extension" > + :reader (read-from-minibuffer > + "Filter by filename extension without separator (regex): ")) > + (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name)) > + (string-match qualifier (or (file-name-extension it) "")))) > + > +;;;###autoload (autoload 'ibuffer-filter-by-directory "ibuf-ext") > +(define-ibuffer-filter directory > + "Limit current view to buffers with directory matching QUALIFIER. > + > +For a buffer associated with file '/a/b/c.d', this matches > +against '/a/b'. For a buffer not associated with a file, this > +matches against the value of `default-directory' in that buffer." > + (:description "directory name" > + :reader (read-from-minibuffer "Filter by directory name (regex): ")) > + (ibuffer-aif (with-current-buffer buf (ibuffer-buffer-file-name)) > + (let ((dirname (file-name-directory it))) > + (when dirname (string-match qualifier dirname))) > + (when default-directory (string-match qualifier default-directory)))) > + > ;;;###autoload (autoload 'ibuffer-filter-by-size-gt "ibuf-ext") > (define-ibuffer-filter size-gt > - "Toggle current view to buffers with size greater than QUALIFIER." > + "Limit current view to buffers with size greater than QUALIFIER." > (:description "size greater than" > :reader > (string-to-number (read-from-minibuffer "Filter by size greater than: > "))) > @@ -1177,16 +1324,32 @@ size-gt > > ;;;###autoload (autoload 'ibuffer-filter-by-size-lt "ibuf-ext") > (define-ibuffer-filter size-lt > - "Toggle current view to buffers with size less than QUALIFIER." > + "Limit current view to buffers with size less than QUALIFIER." > (:description "size less than" > :reader > (string-to-number (read-from-minibuffer "Filter by size less than: "))) > (< (with-current-buffer buf (buffer-size)) > qualifier)) > > +;;;###autoload (autoload 'ibuffer-filter-by-modified "ibuf-ext") > +(define-ibuffer-filter modified > + "Limit current view to buffers that are marked as modified." > + (:description "modified" > + :reader nil) > + (ignore qualifier) > + (buffer-modified-p buf)) > + > +;;;###autoload (autoload 'ibuffer-filter-by-visiting-file "ibuf-ext") > +(define-ibuffer-filter visiting-file > + "Limit current view to buffers that are visiting a file." > + (:description "visiting a file" > + :reader nil) > + (ignore qualifier) > + (with-current-buffer buf (buffer-file-name))) > + > ;;;###autoload (autoload 'ibuffer-filter-by-content "ibuf-ext") > (define-ibuffer-filter content > - "Toggle current view to buffers whose contents match QUALIFIER." > + "Limit current view to buffers whose contents match QUALIFIER." > (:description "content" > :reader (read-from-minibuffer "Filter by content (regexp): ")) > (with-current-buffer buf > @@ -1196,12 +1359,33 @@ content > > ;;;###autoload (autoload 'ibuffer-filter-by-predicate "ibuf-ext") > (define-ibuffer-filter predicate > - "Toggle current view to buffers for which QUALIFIER returns non-nil." > + "Limit current view to buffers for which QUALIFIER returns non-nil." > (:description "predicate" > :reader (read-minibuffer "Filter by predicate (form): ")) > (with-current-buffer buf > (eval qualifier))) > > +;;;###autoload (autoload 'ibuffer-filter-chosen-by-completion "ibuf-ext") > +(defun ibuffer-filter-chosen-by-completion () > + "Select and apply filter chosen by completion against available filters. > +Indicates corresponding key sequences in echo area after filtering. > + > +The completion matches against the filter description text of > +each filter in `ibuffer-filtering-alist'." > + (interactive) > + (let* ((filters (mapcar (lambda (x) (cons (cadr x) (car x))) > + ibuffer-filtering-alist)) > + (match (completing-read "Filter by: " filters nil t)) > + (filter (cdr (assoc match filters))) > + (command (intern (concat "ibuffer-filter-by-" (symbol-name > filter))))) > + (call-interactively command) > + (message "%s can be run with key sequences: %s" > + command > + (mapconcat #'key-description > + (where-is-internal command ibuffer-mode-map nil t) > + "or ")))) > + > + > ;;; Sorting > > ;;;###autoload > diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el > index 94cee32..5a74084 100644 > --- a/lisp/ibuffer.el > +++ b/lisp/ibuffer.el > @@ -518,26 +518,37 @@ ibuffer-mode-map > (define-key map (kbd "s f") 'ibuffer-do-sort-by-filename/process) > (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode) > > + (define-key map (kbd "/ RET") 'ibuffer-filter-by-mode) > (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode) > (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode) > (define-key map (kbd "/ n") 'ibuffer-filter-by-name) > - (define-key map (kbd "/ c") 'ibuffer-filter-by-content) > - (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate) > + (define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name) > (define-key map (kbd "/ f") 'ibuffer-filter-by-filename) > - (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt) > + (define-key map (kbd "/ b") 'ibuffer-filter-by-basename) > + (define-key map (kbd "/ .") 'ibuffer-filter-by-file-extension) > (define-key map (kbd "/ <") 'ibuffer-filter-by-size-lt) > + (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt) > + (define-key map (kbd "/ i") 'ibuffer-filter-by-modified) > + (define-key map (kbd "/ v") 'ibuffer-filter-by-visiting-file) > + (define-key map (kbd "/ c") 'ibuffer-filter-by-content) > + (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate) > + > (define-key map (kbd "/ r") 'ibuffer-switch-to-saved-filters) > (define-key map (kbd "/ a") 'ibuffer-add-saved-filters) > (define-key map (kbd "/ x") 'ibuffer-delete-saved-filters) > (define-key map (kbd "/ d") 'ibuffer-decompose-filter) > (define-key map (kbd "/ s") 'ibuffer-save-filters) > (define-key map (kbd "/ p") 'ibuffer-pop-filter) > + (define-key map (kbd "/ ") 'ibuffer-pop-filter) > (define-key map (kbd "/ !") 'ibuffer-negate-filter) > (define-key map (kbd "/ t") 'ibuffer-exchange-filters) > (define-key map (kbd "/ TAB") 'ibuffer-exchange-filters) > (define-key map (kbd "/ o") 'ibuffer-or-filter) > + (define-key map (kbd "/ |") 'ibuffer-or-filter) > + (define-key map (kbd "/ &") 'ibuffer-and-filter) > (define-key map (kbd "/ g") 'ibuffer-filters-to-filter-group) > (define-key map (kbd "/ P") 'ibuffer-pop-filter-group) > + (define-key map (kbd "/ S-") 'ibuffer-pop-filter-group) > (define-key map (kbd "/ D") 'ibuffer-decompose-filter-group) > (define-key map (kbd "/ /") 'ibuffer-filter-disable) > > @@ -657,13 +668,43 @@ ibuffer-mode-map > ibuffer-filter-by-derived-mode)) > (define-key-after map [menu-bar view filter filter-by-name] > '(menu-item "Add filter by buffer name..." ibuffer-filter-by-name)) > + (define-key-after map [menu-bar view filter filter-by-starred-name] > + '(menu-item "Add filter by starred buffer name..." > + ibuffer-filter-by-starred-name > + :help "List buffers whose names begin with a star")) > (define-key-after map [menu-bar view filter filter-by-filename] > - '(menu-item "Add filter by filename..." ibuffer-filter-by-filename)) > + '(menu-item "Add filter by full filename..." > ibuffer-filter-by-filename > + :help > + (concat "For a buffer associated with file '/a/b/c.d', " > + "list buffer if a given pattern matches > '/a/b/c.d'"))) > + (define-key-after map [menu-bar view filter filter-by-basename] > + '(menu-item "Add filter by file basename..." > + ibuffer-filter-by-basename > + :help (concat "For a buffer associated with file > '/a/b/c.d', " > + "list buffer if a given pattern matches > 'c.d'"))) > + (define-key-after map [menu-bar view filter filter-by-file-extension] > + '(menu-item "Add filter by file name extension..." > + ibuffer-filter-by-file-extension > + :help (concat "For a buffer associated with file > '/a/b/c.d', " > + "list buffer if a given pattern matches > 'd'"))) > + (define-key-after map [menu-bar view filter filter-by-directory] > + '(menu-item "Add filter by filename's directory..." > + ibuffer-filter-by-directory > + :help > + (concat "For a buffer associated with file '/a/b/c.d', " > + "list buffer if a given pattern matches > '/a/b'"))) > (define-key-after map [menu-bar view filter filter-by-size-lt] > '(menu-item "Add filter by size less than..." > ibuffer-filter-by-size-lt)) > (define-key-after map [menu-bar view filter filter-by-size-gt] > '(menu-item "Add filter by size greater than..." > ibuffer-filter-by-size-gt)) > + (define-key-after map [menu-bar view filter filter-by-modified] > + '(menu-item "Add filter by modified buffer" > ibuffer-filter-by-modified > + :help "List buffers that are marked as modified")) > + (define-key-after map [menu-bar view filter filter-by-visiting-file] > + '(menu-item "Add filter by buffer visiting a file" > + ibuffer-filter-by-visiting-file > + :help "List buffers that are visiting files")) > (define-key-after map [menu-bar view filter filter-by-content] > '(menu-item "Add filter by content (regexp)..." > ibuffer-filter-by-content)) > @@ -673,6 +714,12 @@ ibuffer-mode-map > (define-key-after map [menu-bar view filter pop-filter] > '(menu-item "Remove top filter" ibuffer-pop-filter > :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers))) > + (define-key-after map [menu-bar view filter and-filter] > + '(menu-item "AND top two filters" ibuffer-and-filter > + :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers > + (cdr ibuffer-filtering-qualifiers)) > + :help > + "Create a new filter which is the logical AND of the top two > filters")) > (define-key-after map [menu-bar view filter or-filter] > '(menu-item "OR top two filters" ibuffer-or-filter > :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers > diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el > index 92ed101..40760ab 100644 > --- a/test/lisp/ibuffer-tests.el > +++ b/test/lisp/ibuffer-tests.el > @@ -24,7 +24,8 @@ > (require 'ibuf-macs)) > > (ert-deftest ibuffer-autoload () > - "Tests to see whether reftex-auc has been autoloaded" > + "Tests to see whether ibuffer has been autoloaded" > + (skip-unless (not (featurep 'ibuf-ext))) > (should > (fboundp 'ibuffer-mark-unsaved-buffers)) > (should > @@ -138,5 +139,669 @@ > (should-not ibuffer-filtering-qualifiers)) > (setq ibuffer-filtering-qualifiers filters)))) > > +;; Test Filter Inclusion > +(let* (test-buffer-list ; accumulated buffers to clean up > + ;; Utility functions without polluting the environment > + (set-buffer-mode > + (lambda (buffer mode) > + "Set BUFFER's major mode to MODE, a mode function, or > fundamental." > + (with-current-buffer buffer > + (funcall (or mode #'fundamental-mode))))) > + (set-buffer-contents > + (lambda (buffer size include-content) > + "Add exactly SIZE bytes to BUFFER, including INCLUDE-CONTENT." > + (when (or size include-content) > + (let* ((unit "\n") > + (chunk "ccccccccccccccccccccccccccccccc\n") > + (chunk-size (length chunk)) > + (size (if (and size include-content (stringp > include-content)) > + (- size (length include-content)) > + size))) > + (unless (or (null size) (> size 0)) > + (error "size argument must be nil or positive")) > + (with-current-buffer buffer > + (when include-content > + (insert include-content)) > + (when size > + (dotimes (_ (floor size chunk-size)) > + (insert chunk)) > + (dotimes (_ (mod size chunk-size)) > + (insert unit))) > + ;; prevent query on cleanup > + (set-buffer-modified-p nil)))))) > + (create-file-buffer > + (lambda (prefix &rest args-plist) > + "Create a file and buffer with designated properties. > + PREFIX is a string giving the beginning of the name, and > ARGS-PLIST > + is a series of keyword-value pairs, with allowed keywords > + :suffix STRING, :size NUMBER, :mode MODE-FUNC, :include-content > STRING. > + Returns the created buffer." > + (let* ((suffix (plist-get args-plist :suffix)) > + (size (plist-get args-plist :size)) > + (include (plist-get args-plist :include-content)) > + (mode (plist-get args-plist :mode)) > + (file (make-temp-file prefix nil suffix)) > + (buf (find-file-noselect file t))) > + (push buf test-buffer-list) ; record for cleanup > + (funcall set-buffer-mode buf mode) > + (funcall set-buffer-contents buf size include) > + buf))) > + (create-non-file-buffer > + (lambda (prefix &rest args-plist) > + "Create a non-file and buffer with designated properties. > + PREFIX is a string giving the beginning of the name, and > ARGS-PLIST > + is a series of keyword-value pairs, with allowed keywords > + :size NUMBER, :mode MODE-FUNC, :include-content STRING. > + Returns the created buffer." > + (let* ((size (plist-get args-plist :size)) > + (include (plist-get args-plist :include-content)) > + (mode (plist-get args-plist :mode)) > + (buf (generate-new-buffer prefix))) > + (push buf test-buffer-list) ; record for cleanup > + (funcall set-buffer-mode buf mode) > + (funcall set-buffer-contents buf size include) > + buf))) > + (clean-up > + (lambda () > + "Restore all emacs state modified during the tests" > + (while test-buffer-list ; created temporary buffers > + (let ((buf (pop test-buffer-list))) > + (with-current-buffer buf (bury-buffer)) ; ensure not > selected > + (kill-buffer buf)))))) > + ;; Tests > + (ert-deftest ibuffer-filter-inclusion-1 () > + "Tests inclusion using basic filter combinators with a single buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-file-buffer "ibuf-test-1" :size 100 > + :include-content "One ring to rule them all\n"))) > + (should (ibuffer-included-in-filters-p buf '((size-gt . 99)))) > + (should (ibuffer-included-in-filters-p buf '((size-lt . 101)))) > + (should (ibuffer-included-in-filters-p > + buf '((mode . fundamental-mode)))) > + (should (ibuffer-included-in-filters-p > + buf '((content . "ring to rule them all")))) > + (should (ibuffer-included-in-filters-p > + buf '((and (content . "ring to rule them all"))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (and (content . "ring to rule them > all")))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (and (and (content . "ring to rule them > all"))))))) > + (should (ibuffer-included-in-filters-p > + buf '((or (content . "ring to rule them all"))))) > + (should (ibuffer-included-in-filters-p > + buf '((not (not (content . "ring to rule them > all")))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (size-gt . 99) > + (content . "ring to rule them all") > + (mode . fundamental-mode) > + (basename . "\\`ibuf-test-1"))))) > + (should (ibuffer-included-in-filters-p > + buf '((not (or (not (size-gt . 99)) > + (not (content . "ring to rule them > all")) > + (not (mode . fundamental-mode)) > + (not (basename . "\\`ibuf-test-1"))))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (or (size-gt . 99) (size-lt . 10)) > + (and (content . "ring.*all") > + (content . "rule") > + (content . "them all") > + (content . "One")) > + (not (mode . text-mode)) > + (basename . "\\`ibuf-test-1")))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-2 () > + "Tests inclusion of basic filters in combination on a single buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-file-buffer "ibuf-test-2" :size 200 > + :mode #'text-mode > + :include-content "and in the darkness find > them\n"))) > + (should (ibuffer-included-in-filters-p buf '((size-gt . 199)))) > + (should (ibuffer-included-in-filters-p buf '((size-lt . 201)))) > + (should (ibuffer-included-in-filters-p buf '((not size-gt . > 200)))) > + (should (ibuffer-included-in-filters-p buf '((not (size-gt . > 200))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (size-gt . 199) (size-lt . 201))))) > + (should (ibuffer-included-in-filters-p > + buf '((or (size-gt . 199) (size-gt . 201))))) > + (should (ibuffer-included-in-filters-p > + buf '((or (size-gt . 201) (size-gt . 199))))) > + (should (ibuffer-included-in-filters-p > + buf '((size-gt . 199) (mode . text-mode) > + (content . "darkness find them")))) > + (should (ibuffer-included-in-filters-p > + buf '((and (size-gt . 199) (mode . text-mode) > + (content . "darkness find them"))))) > + (should (ibuffer-included-in-filters-p > + buf '((not (or (not (size-gt . 199)) (not (mode . > text-mode)) > + (not (content . "darkness find > them"))))))) > + (should (ibuffer-included-in-filters-p > + buf '((or (size-gt . 200) (content . "darkness find > them") > + (derived-mode . emacs-lisp-mode))))) > + (should-not (ibuffer-included-in-filters-p > + buf '((or (size-gt . 200) (content . "rule them > all") > + (derived-mode . emacs-lisp-mode)))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-3 () > + "Tests inclusion with filename filters on specified buffers." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let* ((bufA > + (funcall create-file-buffer "ibuf-test-3.a" :size 50 > + :mode #'text-mode > + :include-content "...but a multitude of > drops?\n")) > + (bufB > + (funcall create-non-file-buffer "ibuf-test-3.b" :size 50 > + :mode #'text-mode > + :include-content "...but a multitude of > drops?\n")) > + (dirA (with-current-buffer bufA default-directory)) > + (dirB (with-current-buffer bufB default-directory))) > + (should (ibuffer-included-in-filters-p > + bufA '((basename . "ibuf-test-3")))) > + (should (ibuffer-included-in-filters-p > + bufA '((basename . "test-3\\.a")))) > + (should (ibuffer-included-in-filters-p > + bufA '((file-extension . "a")))) > + (should (ibuffer-included-in-filters-p > + bufA (list (cons 'directory dirA)))) > + (should-not (ibuffer-included-in-filters-p > + bufB '((basename . "ibuf-test-3")))) > + (should-not (ibuffer-included-in-filters-p > + bufB '((file-extension . "b")))) > + (should (ibuffer-included-in-filters-p > + bufB (list (cons 'directory dirB)))) > + (should (ibuffer-included-in-filters-p > + bufA '((name . "ibuf-test-3")))) > + (should (ibuffer-included-in-filters-p > + bufB '((name . "ibuf-test-3"))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-4 () > + "Tests inclusion with various filters on a single buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-file-buffer "ibuf-test-4" > + :mode #'emacs-lisp-mode :suffix ".el" > + :include-content "(message \"--%s--\" > 'emacs-rocks)\n"))) > + (should (ibuffer-included-in-filters-p > + buf '((file-extension . "el")))) > + (should (ibuffer-included-in-filters-p > + buf '((derived-mode . prog-mode)))) > + (should (ibuffer-included-in-filters-p > + buf '((used-mode . emacs-lisp-mode)))) > + (should (ibuffer-included-in-filters-p > + buf '((mode . emacs-lisp-mode)))) > + (with-current-buffer buf (set-buffer-modified-p t)) > + (should (ibuffer-included-in-filters-p buf '((modified)))) > + (with-current-buffer buf (set-buffer-modified-p nil)) > + (should (ibuffer-included-in-filters-p buf '((not modified)))) > + (should (ibuffer-included-in-filters-p > + buf '((and (file-extension . "el") > + (derived-mode . prog-mode) > + (not modified))))) > + (should (ibuffer-included-in-filters-p > + buf '((or (file-extension . "tex") > + (derived-mode . prog-mode) > + (modified))))) > + (should (ibuffer-included-in-filters-p > + buf '((file-extension . "el") > + (derived-mode . prog-mode) > + (not modified))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-5 () > + "Tests inclusion with various filters on a single buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-non-file-buffer "ibuf-test-5.el" > + :mode #'emacs-lisp-mode > + :include-content > + "(message \"--%s--\" \"It really does!\")\n"))) > + (should-not (ibuffer-included-in-filters-p > + buf '((file-extension . "el")))) > + (should (ibuffer-included-in-filters-p > + buf '((size-gt . 18)))) > + (should (ibuffer-included-in-filters-p > + buf '((predicate . (lambda () > + (> (- (point-max) (point-min)) > 18)))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (mode . emacs-lisp-mode) > + (or (starred-name) > + (size-gt . 18)) > + (and (not (size-gt . 100)) > + (content . "[Ii]t *really does!") > + (or (name . "test-5") > + (not (filename . "test-5"))))))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-6 () > + "Tests inclusion using saved filters and DeMorgan's laws." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-non-file-buffer "*ibuf-test-6*" :size 65 > + :mode #'text-mode)) > + (buf2 > + (funcall create-file-buffer "ibuf-test-6a" :suffix ".html" > + :mode #'html-mode > + :include-content > + "

Hello, > World!

"))) > + (should (ibuffer-included-in-filters-p buf '((starred-name)))) > + (should-not (ibuffer-included-in-filters-p > + buf '((saved . "text document")))) > + (should (ibuffer-included-in-filters-p buf2 '((saved . "web")))) > + (should (ibuffer-included-in-filters-p > + buf2 '((not (and (not (derived-mode . sgml-mode)) > + (not (derived-mode . css-mode)) > + (not (mode . javascript-mode)) > + (not (mode . js2-mode)) > + (not (mode . scss-mode)) > + (not (derived-mode . haml-mode)) > + (not (mode . sass-mode))))))) > + (should (ibuffer-included-in-filters-p > + buf '((and (starred-name) > + (or (size-gt . 50) (filename . "foo")))))) > + (should (ibuffer-included-in-filters-p > + buf '((not (or (not starred-name) > + (and (size-lt . 51) > + (not (filename . "foo"))))))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-7 () > + "Tests inclusion with various filters on a single buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((buf > + (funcall create-non-file-buffer "ibuf-test-7" > + :mode #'artist-mode))) > + (should (ibuffer-included-in-filters-p > + buf '((not (starred-name))))) > + (should (ibuffer-included-in-filters-p > + buf '((not starred-name)))) > + (should (ibuffer-included-in-filters-p > + buf '((not (not (not starred-name)))))) > + (should (ibuffer-included-in-filters-p > + buf '((not (modified))))) > + (should (ibuffer-included-in-filters-p > + buf '((not modified)))) > + (should (ibuffer-included-in-filters-p > + buf '((not (not (not modified))))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-filter-inclusion-8 () > + "Tests inclusion with various filters." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((bufA > + (funcall create-non-file-buffer "ibuf-test-8a" > + :mode #'artist-mode)) > + (bufB (funcall create-non-file-buffer "*ibuf-test-8b*" > :size 32)) > + (bufC (funcall create-file-buffer "ibuf-test8c" :suffix "*" > + :size 64)) > + (bufD (funcall create-file-buffer "*ibuf-test8d" :size 128)) > + (bufE (funcall create-file-buffer "*ibuf-test8e" :suffix > "*<2>" > + :size 16)) > + (bufF (and (funcall create-non-file-buffer "*ibuf-test8f*") > + (funcall create-non-file-buffer "*ibuf-test8f*" > + :size 8)))) > + (with-current-buffer bufA (set-buffer-modified-p t)) > + (should (ibuffer-included-in-filters-p > + bufA '((and (not starred-name) > + (modified) > + (name . "test-8") > + (not (size-gt . 100)) > + (mode . picture-mode))))) > + (with-current-buffer bufA (set-buffer-modified-p nil)) > + (should-not (ibuffer-included-in-filters-p > + bufA '((or (starred-name) (visiting-file) > (modified))))) > + (should (ibuffer-included-in-filters-p > + bufB '((and (starred-name) > + (name . "test.*8b") > + (size-gt . 31) > + (not visiting-file))))) > + (should (ibuffer-included-in-filters-p > + bufC '((and (not (starred-name)) > + (visiting-file) > + (name . "8c[^*]*\\*") > + (size-lt . 65))))) > + (should (ibuffer-included-in-filters-p > + bufD '((and (not (starred-name)) > + (visiting-file) > + (name . "\\`\\*.*test8d") > + (size-lt . 129) > + (size-gt . 127))))) > + (should (ibuffer-included-in-filters-p > + bufE '((and (starred-name) > + (visiting-file) > + (name . "8e.*?\\*<[[:digit:]]+>") > + (size-gt . 10))))) > + (should (ibuffer-included-in-filters-p > + bufF '((and (starred-name) > + (not (visiting-file)) > + (name . "8f\\*<[[:digit:]]>") > + (size-lt . 10)))))) > + (funcall clean-up)))) > + > +;; Test Filter Combination and Decomposition > +(let* (ibuffer-to-kill ; if non-nil, kill this buffer at cleanup > + (ibuffer-already 'check) ; existing ibuffer buffer to use but not > kill > + ;; Utility functions without polluting the environment > + (get-test-ibuffer > + (lambda () > + "Returns a test ibuffer-mode buffer, creating one if necessary. > + If a new buffer is created, it is named \"*Test-Ibuffer*\" and is > + saved to `ibuffer-to-kill' for later cleanup." > + (when (eq ibuffer-already 'check) > + (setq ibuffer-already > + (catch 'found-buf > + (dolist (buf (buffer-list) nil) > + (when (with-current-buffer buf > + (derived-mode-p 'ibuffer-mode)) > + (throw 'found-buf buf)))))) > + (or ibuffer-already > + ibuffer-to-kill > + (let ((test-ibuf-name "*Test-Ibuffer*")) > + (ibuffer nil test-ibuf-name nil t) > + (setq ibuffer-to-kill (get-buffer test-ibuf-name)))))) > + (clean-up > + (lambda () > + "Restore all emacs state modified during the tests" > + (when ibuffer-to-kill ; created ibuffer > + (with-current-buffer ibuffer-to-kill > + (set-buffer-modified-p nil) > + (bury-buffer)) > + (kill-buffer ibuffer-to-kill) > + (setq ibuffer-to-kill nil)) > + (when (and ibuffer-already (not (eq ibuffer-already 'check))) > + ;; restore existing ibuffer state > + (ibuffer-update nil t))))) > + ;; Tests > + (ert-deftest ibuffer-decompose-filter () > + "Tests `ibuffer-decompose-filter' for and, or, not, and saved." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((ibuf (funcall get-test-ibuffer))) > + (with-current-buffer ibuf > + (let ((ibuffer-filtering-qualifiers nil) > + (ibuffer-filter-groups nil) > + (filters '((size-gt . 100) (not (starred-name)) > + (name . "foo")))) > + (progn > + (push (cons 'or filters) ibuffer-filtering-qualifiers) > + (ibuffer-decompose-filter) > + (should (equal filters ibuffer-filtering-qualifiers)) > + (setq ibuffer-filtering-qualifiers nil)) > + (progn > + (push (cons 'and filters) ibuffer-filtering-qualifiers) > + (ibuffer-decompose-filter) > + (should (equal filters ibuffer-filtering-qualifiers)) > + (setq ibuffer-filtering-qualifiers nil)) > + (progn > + (push (list 'not (car filters)) > ibuffer-filtering-qualifiers) > + (ibuffer-decompose-filter) > + (should (equal (list (car filters)) > + ibuffer-filtering-qualifiers)) > + (setq ibuffer-filtering-qualifiers nil)) > + (progn > + (push (cons 'not (car filters)) > ibuffer-filtering-qualifiers) > + (ibuffer-decompose-filter) > + (should (equal (list (car filters)) > + ibuffer-filtering-qualifiers)) > + (setq ibuffer-filtering-qualifiers nil)) > + (let ((gnus (assoc "gnus" ibuffer-saved-filters))) > + (push '(saved . "gnus") ibuffer-filtering-qualifiers) > + (ibuffer-decompose-filter) > + (should (equal (cdr gnus) ibuffer-filtering-qualifiers)) > + (ibuffer-decompose-filter) > + (should (equal (cdr (cadr gnus)) > ibuffer-filtering-qualifiers)) > + (setq ibuffer-filtering-qualifiers nil)) > + (when (not (assoc "__unknown__" ibuffer-saved-filters)) > + (push '(saved . "__uknown__") > ibuffer-filtering-qualifiers) > + (should-error (ibuffer-decompose-filter) :type 'error) > + (setq ibuffer-filtering-qualifiers nil)) > + (progn > + (push (car filters) ibuffer-filtering-qualifiers) > + (should-error (ibuffer-decompose-filter) :type 'error) > + (setq ibuffer-filtering-qualifiers nil))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-and-filter () > + "Tests `ibuffer-and-filter' in an Ibuffer buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((ibuf (funcall get-test-ibuffer))) > + (with-current-buffer ibuf > + (let ((ibuffer-filtering-qualifiers nil) > + (ibuffer-filter-groups nil) > + (filters [(size-gt . 100) (not (starred-name)) > + (filename . "A") (mode . text-mode)])) > + (should-error (ibuffer-and-filter) :type 'error) > + (progn > + (push (aref filters 1) ibuffer-filtering-qualifiers) > + (should-error (ibuffer-and-filter) :type 'error)) > + (should (progn > + (push (aref filters 0) > ibuffer-filtering-qualifiers) > + (ibuffer-and-filter) > + (and (equal (list 'and (aref filters 0) (aref > filters 1)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (should (progn > + (ibuffer-and-filter 'decompose) > + (and (equal (aref filters 0) > + (pop ibuffer-filtering-qualifiers)) > + (equal (aref filters 1) > + (pop ibuffer-filtering-qualifiers)) > + (null ibuffer-filtering-qualifiers)))) > + (should (progn > + (push (list 'and (aref filters 2) (aref filters > 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'and (aref filters 0) (aref filters > 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-and-filter) > + (and (equal (list 'and (aref filters 0) (aref > filters 1) > + (aref filters 2) (aref filters > 3)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'or (aref filters 2) (aref filters 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'and (aref filters 0) (aref filters > 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-and-filter) > + (and (equal (list 'and (aref filters 0) (aref > filters 1) > + (list 'or (aref filters 2) > + (aref filters 3))) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'and (aref filters 2) (aref filters > 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'or (aref filters 0) (aref filters 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-and-filter) > + (and (equal (list 'and (list 'or (aref filters 0) > + (aref filters 1)) > + (aref filters 2) (aref filters > 3)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'or (aref filters 2) (aref filters 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'or (aref filters 0) (aref filters 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-and-filter) > + (and (equal (list 'and > + (list 'or (aref filters 0) > + (aref filters 1)) > + (list 'or (aref filters 2) > + (aref filters 3))) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers)) > )))))) > + (funcall clean-up))) > + > + (ert-deftest ibuffer-or-filter () > + "Tests `ibuffer-or-filter' in an Ibuffer buffer." > + (skip-unless (featurep 'ibuf-ext)) > + (unwind-protect > + (let ((ibuf (funcall get-test-ibuffer))) > + (with-current-buffer ibuf > + (let ((ibuffer-filtering-qualifiers nil) > + (ibuffer-filter-groups nil) > + (filters [(size-gt . 100) (not (starred-name)) > + (filename . "A") (mode . text-mode)])) > + (should-error (ibuffer-or-filter) :type 'error) > + (progn > + (push (aref filters 1) ibuffer-filtering-qualifiers) > + (should-error (ibuffer-or-filter) :type 'error)) > + (should (progn > + (push (aref filters 0) > ibuffer-filtering-qualifiers) > + (ibuffer-or-filter) > + (and (equal (list 'or (aref filters 0) (aref > filters 1)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (should (progn > + (ibuffer-or-filter 'decompose) > + (and (equal (aref filters 0) > + (pop ibuffer-filtering-qualifiers)) > + (equal (aref filters 1) > + (pop ibuffer-filtering-qualifiers)) > + (null ibuffer-filtering-qualifiers)))) > + (should (progn > + (push (list 'or (aref filters 2) (aref filters 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'or (aref filters 0) (aref filters 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-or-filter) > + (and (equal (list 'or (aref filters 0) (aref > filters 1) > + (aref filters 2) (aref filters > 3)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'and (aref filters 2) (aref filters > 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'or (aref filters 0) (aref filters 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-or-filter) > + (and (equal (list 'or (aref filters 0) (aref > filters 1) > + (list 'and (aref filters 2) > + (aref filters 3))) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'or (aref filters 2) (aref filters 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'and (aref filters 0) (aref filters > 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-or-filter) > + (and (equal (list 'or (list 'and (aref filters 0) > + (aref filters 1)) > + (aref filters 2) (aref filters > 3)) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers))))) > + (pop ibuffer-filtering-qualifiers) > + (should (progn > + (push (list 'and (aref filters 2) (aref filters > 3)) > + ibuffer-filtering-qualifiers) > + (push (list 'and (aref filters 0) (aref filters > 1)) > + ibuffer-filtering-qualifiers) > + (ibuffer-or-filter) > + (and (equal (list 'or > + (list 'and (aref filters 0) > + (aref filters 1)) > + (list 'and (aref filters 2) > + (aref filters 3))) > + (car ibuffer-filtering-qualifiers)) > + (null (cdr ibuffer-filtering-qualifiers)) > )))))) > + (funcall clean-up)))) > + > +(ert-deftest ibuffer-format-qualifier () > + "Tests string recommendation of filter from `ibuffer-format-qualifier'." > + (skip-unless (featurep 'ibuf-ext)) > + (let ((test1 '(mode . org-mode)) > + (test2 '(size-lt . 100)) > + (test3 '(derived-mode . prog-mode)) > + (test4 '(or (size-gt . 10000) > + (and (not (starred-name)) > + (directory . "\\")))) > + (test5 '(or (filename . "scratch") > + (filename . "bonz") > + (filename . "temp"))) > + (test6 '(or (mode . emacs-lisp-mode) (file-extension . "elc?") > + (and (starred-name) (name . "elisp")) > + (mode . lisp-interaction-mode))) > + (description (lambda (q) > + (cadr (assq q ibuffer-filtering-alist)))) > + (tag (lambda (&rest args ) > + (concat " [" (apply #'concat args) "]")))) > + (should (equal (ibuffer-format-qualifier test1) > + (funcall tag (funcall description 'mode) > + ": " "org-mode"))) > + (should (equal (ibuffer-format-qualifier test2) > + (funcall tag (funcall description 'size-lt) > + ": " "100"))) > + (should (equal (ibuffer-format-qualifier test3) > + (funcall tag (funcall description 'derived-mode) > + ": " "prog-mode"))) > + (should (equal (ibuffer-format-qualifier test4) > + (funcall tag "OR" > + (funcall tag (funcall description 'size-gt) > + ": " (format "%s" 10000)) > + (funcall tag "AND" > + (funcall tag "NOT" > + (funcall tag > + (funcall > description > + > 'starred-name) > + ": " "nil")) > + (funcall tag > + (funcall description > 'directory) > + ": " "\\"))))) > + (should (equal (ibuffer-format-qualifier test5) > + (funcall tag "OR" > + (funcall tag (funcall description 'filename) > + ": " "scratch") > + (funcall tag (funcall description 'filename) > + ": " "bonz") > + (funcall tag (funcall description 'filename) > + ": " "temp")))) > + (should (equal (ibuffer-format-qualifier test6) > + (funcall tag "OR" > + (funcall tag (funcall description 'mode) > + ": " "emacs-lisp-mode") > + (funcall tag (funcall description > 'file-extension) > + ": " "elc?") > + (funcall tag "AND" > + (funcall tag > + (funcall description > 'starred-name) > + ": " "nil") > + (funcall tag > + (funcall description 'name) > + ": " "elisp")) > + (funcall tag (funcall description 'mode) > + ": " "lisp-interaction-mode")))))) > + > +(ert-deftest ibuffer-unary-operand () > + "Tests `ibuffer-unary-operand': (not cell) or (not . cell) -> cell." > + (skip-unless (featurep 'ibuf-ext)) > + (should (equal (ibuffer-unary-operand '(not . (mode "foo"))) > + '(mode "foo"))) > + (should (equal (ibuffer-unary-operand '(not (mode "foo"))) > + '(mode "foo"))) > + (should (equal (ibuffer-unary-operand '(not "cdr")) > + '("cdr"))) > + (should (equal (ibuffer-unary-operand '(not)) nil)) > + (should (equal (ibuffer-unary-operand '(not . a)) 'a))) > + > (provide 'ibuffer-tests) > ;; ibuffer-tests.el ends here > -- > 2.10.2 > > From 268f9de4ee4ef6cdba9d4c313a52e42653a1067c Mon Sep 17 00:00:00 2001 > From: Christopher Genovese > Date: Fri, 9 Dec 2016 09:13:36 +0900 > Subject: [PATCH 2/2] ibuffer: Update key bindings > > * lisp/ibuffer.el (ibuffer-mode-map): Bind 'ibuffer-filter-by-directory' > and 'ibuffer-filter-chosen-by-completion' to '//' and '/TAB' respectively. > Rebind 'ibuffer-filter-disable' to '/ DEL'. > ; * etc/NEWS: Update NEWS entries. > --- > etc/NEWS | 10 ++++++---- > lisp/ibuffer.el | 5 +++-- > 2 files changed, 9 insertions(+), 6 deletions(-) > > diff --git a/etc/NEWS b/etc/NEWS > index f60deb1..fc2dfe5 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -324,12 +324,14 @@ to '/b', '/.', '//', '/*', '/i' and '/v'. > > --- > *** Two new commands 'ibuffer-filter-chosen-by-completion' > -and `ibuffer-and-filter', the second bound to '/&'. > +and `ibuffer-and-filter'; bound to '/ TAB' and '/&' > +respectively. > > --- > -*** The commands `ibuffer-pop-filter', `ibuffer-pop-filter-group', > -`ibuffer-or-filter' and `ibuffer-filter-disable' have the alternative > -bindings '/', '/S-', '/|' and '/DEL', respectively. > +*** The key binding for `ibuffer-filter-disable' has being changed > +to '/DEL'; the commands `ibuffer-pop-filter', `ibuffer-pop-filter-group' > +and `ibuffer-or-filter' have the alternative bindings '/', '/S-' > +and '/|'. > > --- > *** The data format specifying filters has been extended to allow > diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el > index 5a74084..db9cfeb 100644 > --- a/lisp/ibuffer.el > +++ b/lisp/ibuffer.el > @@ -526,12 +526,14 @@ ibuffer-mode-map > (define-key map (kbd "/ f") 'ibuffer-filter-by-filename) > (define-key map (kbd "/ b") 'ibuffer-filter-by-basename) > (define-key map (kbd "/ .") 'ibuffer-filter-by-file-extension) > + (define-key map (kbd "/ /") 'ibuffer-filter-by-directory) > (define-key map (kbd "/ <") 'ibuffer-filter-by-size-lt) > (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt) > (define-key map (kbd "/ i") 'ibuffer-filter-by-modified) > (define-key map (kbd "/ v") 'ibuffer-filter-by-visiting-file) > (define-key map (kbd "/ c") 'ibuffer-filter-by-content) > (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate) > + (define-key map (kbd "/ TAB") 'ibuffer-filter-chosen-by-completion) > > (define-key map (kbd "/ r") 'ibuffer-switch-to-saved-filters) > (define-key map (kbd "/ a") 'ibuffer-add-saved-filters) > @@ -542,7 +544,6 @@ ibuffer-mode-map > (define-key map (kbd "/ ") 'ibuffer-pop-filter) > (define-key map (kbd "/ !") 'ibuffer-negate-filter) > (define-key map (kbd "/ t") 'ibuffer-exchange-filters) > - (define-key map (kbd "/ TAB") 'ibuffer-exchange-filters) > (define-key map (kbd "/ o") 'ibuffer-or-filter) > (define-key map (kbd "/ |") 'ibuffer-or-filter) > (define-key map (kbd "/ &") 'ibuffer-and-filter) > @@ -550,7 +551,7 @@ ibuffer-mode-map > (define-key map (kbd "/ P") 'ibuffer-pop-filter-group) > (define-key map (kbd "/ S-") 'ibuffer-pop-filter-group) > (define-key map (kbd "/ D") 'ibuffer-decompose-filter-group) > - (define-key map (kbd "/ /") 'ibuffer-filter-disable) > + (define-key map (kbd "/ DEL") 'ibuffer-filter-disable) > > (define-key map (kbd "M-n") 'ibuffer-forward-filter-group) > (define-key map "\t" 'ibuffer-forward-filter-group) > -- > 2.10.2 > > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > ;;;;;;;;;;;;;;;;;;; > In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.4) > of 2016-12-08 > Repository revision: f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1 > --94eb2c088ee26e61870543a39d65 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Tino,

=C2=A0 I = just had a chance to apply the patch, rebuild, and test.

=C2= =A0 Two things:

=C2=A0 1. The "(ignore qualifier)" s= tatement you added to several of the
=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 filters causes the filters to always return nil. Removing this
=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 ignore fixes the problem and makes the tests pa= ss.

=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 But I think this is actually a ne= w problem that was introduced
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 in more rec= ent changes to ibuf-macs.el.=C2=A0 What seems to be happening
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 on first look is that the filter code in de= fine-ibuffer-filter is now wrapped
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 in a = condition-case=C2=A0 inside a lambda making the ignore form the body form <= br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 and thus always giving a nil result.=C2= =A0 In the versions when we started this,
=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 the filter function was directly wrapped in a lambda so = the ignore directive
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 you included could = take effect.
=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Lookin= g in the current version of ibuf-macs.el for the definition of
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 define-ibuffer-filter it has=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (condition-case nil
=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ,@body
=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (error (ibuffer-pop-= filter)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 ...))

=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 b= ut I think this should have the spliced ,@body wrapped in a progn.
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 That would also solve the proble= m. Whether the ignore would suppress
=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 the compiler warnings in that position as you intended, = I'm not sure.

=C2=A0=C2=A0 2. This patch r= emoved the additional default saved filters that I had added
= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ("TeX", "text document&= quot;, "web"), which is fine.=C2=A0 But one of my tests
=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 used one of those saved filters b= ecause I had it predefined in ibuffer-saved-filters.=C2=A0
=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 It's an easy change either way to fix this.
=C2=A0All the other tests pass without a problem.

= =C2=A0 Let me know how you'd like me to proceed.

=
=C2=A0-- Chris


On Thu, Dec 8, 2016 at 8:00 PM, Tino Calancha <tino.calancha@gmail.com> wrote:
Tino Calancha <tino.calancha@gmail.com> writes:

> Christopher Genovese <genovese@= cmu.edu> writes:
>
>> Tino,
>>
>>=C2=A0 =C2=A0Sorry it took so long to get this to you; it's bee= n a crazy week.
>> I've attached a patch file with all the changes we have discus= sed
>> (except one, see below) to the code, change logs, and NEWS
> Without the fix to Bug#25049 is easier to review.=C2=A0 Thank you!
> You made a great job and very fast!
>
> I have divided the patch in two parts.

Hi Chris,

This week ibuffer.el and ibuf-ext.el have changed significatly
for bug fixing.=C2=A0 I have updated your patch in this thread to
be applied on top of the current master branch.

Let's test a few days more this updated patch to confirm that
everything works as expected.

The updated patch can be applied to the current state of the
master branch, i.e., currently the commit
f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1

Regards,
Tino

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;;;;;;;;;;
>From 1cffd494f352c8b990d36e99cebd8f70e746d6c4 Mon Sep 17 00:00:00 2001=
From: Christopher Genovese <genovese= @cmu.edu>
Date: Fri, 9 Dec 2016 09:13:06 +0900
Subject: [PATCH 1/2] ibuffer: New filters and comman= ds

Add several new filters and improve documentation.
See discussion on:
https://lists.gnu.org/archive/html/emacs-devel/2016-11/msg00399.html
* lisp/ibuf-ext.el: Add paragraph to file commentary.
(ibuffer-saved-filters, ibuffer-filtering-qualifiers)
(ibuffer-filter-groups): Update doc string.
(ibuffer-unary-operand): Add new function that transparently
handles 'not' formats for compound filters.
(ibuffer-included-in-filter-p): Handle 'not' fully; update doc= string.
(ibuffer-included-in-filter-p-1): Handle 'and' compound filter= s.
(ibuffer-decompose-filter): Handle 'and' as well,
and handle 'not' consistently with other uses.
(ibuffer-and-filter): New defun analogous to 'ibuffer-or-filter'. (ibuffer--or-and-filter): New defun.
(ibuffer-or-filter, ibuffer-and-filter): Use it.
(ibuffer-format-qualifier): Handle 'and' filters as well.
(ibuffer-filter-by-basename, ibuffer-filter-by-file-extension)
(ibuffer-filter-by-directory, ibuffer-filter-by-starred-name)
(ibuffer-filter-by-modified, ibuffer-filter-by-visiting-file):
Add new pre-defined filters.
(ibuffer-filter-chosen-by-completion): Add new interactive command
for easily choosing a filter from the descriptions.
* lisp/ibuffer.el (ibuffer-mode-map):
Bind ibuffer-filter-by-basename, ibuffer-filter-by-file-extension,
ibuffer-filter-by-starred-name, ibuffer-filter-by-modified,
ibuffer-filter-by-visiting-file to '/b', '/.', '/*= ', '/i', '/v'
respectively; bind 'ibuffer-or-filter', 'ibuffer-and-filter'= ;,
'ibuffer-pop-filter' ,'ibuffer-pop-filter-group' and
'ibuffer-filter-disable' to '/|', '/&', '/&= lt;up>', '/S-<up>'
and '/ DEL' respectively.
* test/lisp/ibuffer-tests.el (ibuffer-autoload): Add appropriate
skip specification.
Add menu entries for the new filters.
(ibuffer-filter-inclusion-1, ibuffer-filter-inclusion-2
ibuffer-filter-inclusion-3, ibuffer-filter-inclusion-4
ibuffer-filter-inclusion-5, ibuffer-filter-inclusion-6
ibuffer-filter-inclusion-7, ibuffer-filter-inclusion-8
ibuffer-decompose-filter, ibuffer-and-filter
ibuffer-or-filter): Add new tests; they are skipped unless
ibuf-ext is loaded.
; * etc/NEWS: Add entries for new user-facing features.
---
=C2=A0etc/NEWS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0|=C2=A0 21 ++
=C2=A0lisp/ibuf-ext.el=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= | 318 ++++++++++++++++-----
=C2=A0lisp/ibuffer.el=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 55 += ++-
=C2=A0test/lisp/ibuffer-tests.el | 667 +++++++++++++++++++++++++++++++= +++++++++++++-
=C2=A04 files changed, 989 insertions(+), 72 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index a62668a..f60deb1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -316,6 +316,27 @@ bound to 'Buffer-menu-unmark-all-buffers'= .
=C2=A0** Ibuffer

=C2=A0---
+*** New filter commands `ibuffer-filter-by-basename',
+`ibuffer-filter-by-file-extension', `ibuffer-filter-by-directory&= #39;,
+`ibuffer-filter-by-starred-name', `ibuffer-filter-by-modified'= ;
+and `ibuffer-filter-by-visiting-file'; bound respectively
+to '/b', '/.', '//', '/*', '/i' an= d '/v'.
+
+---
+*** Two new commands 'ibuffer-filter-chosen-by-completion' +and `ibuffer-and-filter', the second bound to '/&'.
+
+---
+*** The commands `ibuffer-pop-filter', `ibuffer-pop-filter-group',=
+`ibuffer-or-filter' and `ibuffer-filter-disable' have the alternat= ive
+bindings '/<up>', '/S-<up>', '/|' and = '/DEL', respectively.
+
+---
+*** The data format specifying filters has been extended to allow
+explicit logical 'and', and a more flexible form for logical '= not'.
+See 'ibuffer-filtering-qualifiers' doc string for full details. +
+---
=C2=A0*** A new command 'ibuffer-copy-buffername-as-kill'; bou= nd
=C2=A0to 'B'.

diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index 9ce7b5a..d1e70b6 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -28,6 +28,13 @@
=C2=A0;; These functions should be automatically loaded when called, but yo= u
=C2=A0;; can explicitly (require 'ibuf-ext) in your ~/.emacs to have th= em
=C2=A0;; preloaded.
+;;
+;; For details on the structure of ibuffer filters and filter groups,
+;; see the documentation for variables `ibuffer-filtering-qualifiers'<= wbr>,
+;; `ibuffer-filter-groups', and `ibuffer-saved-filters' in that or= der.
+;; The variable `ibuffer-filtering-alist' contains names and
+;; descriptions of the currently defined filters; also see the macro
+;; `define-ibuffer-filter'.

=C2=A0;;; Code:

@@ -214,8 +221,48 @@ ibuffer-old-saved-filters-warning
=C2=A0"))

=C2=A0(defvar ibuffer-filtering-qualifiers nil
-=C2=A0 "A list like (SYMBOL . QUALIFIER) which filters the current bu= ffer list.
-See also `ibuffer-filtering-alist'.")
+=C2=A0 "A list specifying the filters currently acting on the buffer = list.
+
+If this list is nil, then no filters are currently in
+effect. Otherwise, each element of this list specifies a single
+filter, and all of the specified filters in the list are applied
+successively to the buffer list.
+
+Each filter specification can be of two types: simple or compound.
+
+A simple filter specification has the form (SYMBOL . QUALIFIER),
+where SYMBOL is a key in the alist `ibuffer-filtering-alist' that
+determines the filter function to use and QUALIFIER is the data
+passed to that function (along with the buffer being considered).
+
+A compound filter specification can have one of four forms:
+
+-- (not FILTER-SPEC)
+
+=C2=A0 =C2=A0Represents the logical complement of FILTER-SPEC, which
+=C2=A0 =C2=A0is any single filter specification, simple or compound.
+=C2=A0 =C2=A0The form (not . FILTER-SPEC) is also accepted here.
+
+-- (and FILTER-SPECS...)
+
+=C2=A0 =C2=A0Represents the logical-and of the filters defined by one or +=C2=A0 =C2=A0more filter specifications FILTER-SPECS..., where each
+=C2=A0 =C2=A0specification can be simple or compound.=C2=A0 Note that and = is
+=C2=A0 =C2=A0implicitly applied to the filters in the top-level list.
+
+-- (or FILTER-SPECS...)
+
+=C2=A0 =C2=A0Represents the logical-or of the filters defined by one or +=C2=A0 =C2=A0more filter specifications FILTER-SPECS..., where each
+=C2=A0 =C2=A0specification can be simple or compound.
+
+-- (saved . \"NAME\")
+
+=C2=A0 =C2=A0Represents the filter saved under the string NAME
+=C2=A0 =C2=A0in the alist `ibuffer-saved-filters'. It is an
+=C2=A0 =C2=A0error to name a filter that has not been saved.
+
+This variable is local to each ibuffer buffer.")

=C2=A0;; This is now frobbed by `define-ibuffer-filter'.
=C2=A0(defvar ibuffer-filtering-alist nil
@@ -247,10 +294,18 @@ ibuffer-cached-filter-formats
=C2=A0(defvar ibuffer-compiled-filter-formats nil)
=C2=A0(defvar ibuffer-filter-groups nil
-=C2=A0 "A list like ((\"NAME\" ((SYMBOL . QUALIFIER) ...) .= ..) which groups buffers.
-The SYMBOL should be one from `ibuffer-filtering-alist'.
-The QUALIFIER should be the same as QUALIFIER in
-`ibuffer-filtering-qualifiers'.")
+=C2=A0 "An alist giving this buffer's active filter groups, or ni= l if none.
+
+This alist maps filter group labels to filter specification
+lists.=C2=A0 Each element has the form (\"LABEL\" FILTER-SPECS..= .),
+where FILTER-SPECS... represents one or more filter
+specifications of the same form as allowed as elements of
+`ibuffer-filtering-qualifiers'.
+
+Each filter group is displayed as a separate section in the
+ibuffer list, headed by LABEL and displaying only the buffers
+that pass through all the filters associated with NAME in this
+list.")

=C2=A0(defcustom ibuffer-show-empty-filter-groups t
=C2=A0 =C2=A0"If non-nil, then show the names of filter groups which a= re empty."
@@ -260,20 +315,21 @@ ibuffer-show-empty-filter-groups
=C2=A0(defcustom ibuffer-saved-filter-groups nil
=C2=A0 =C2=A0"An alist of filtering groups to switch between.

-This variable should look like ((\"STRING\" QUALIFIERS)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (\"STRING\" QUALIFIERS) ..= .), where
-QUALIFIERS is a list of the same form as
-`ibuffer-filtering-qualifiers'.
+Each element is of the form (\"NAME\" . FILTER-GROUP-LIST),
+where NAME is a unique but arbitrary name and FILTER-GROUP-LIST
+is a list of filter groups with the same structure as
+allowed for `ibuffer-filter-groups'.

-See also the variables `ibuffer-filter-groups',
-`ibuffer-filtering-qualifiers', `ibuffer-filtering-alist', an= d the
-functions `ibuffer-switch-to-saved-filter-groups',
-`ibuffer-save-filter-groups'."
+See also the functions `ibuffer-save-filter-groups' and
+`ibuffer-switch-to-saved-filter-groups' for saving and switching<= br> +between sets of filter groups, and the variable
+`ibuffer-save-with-custom' that affects how this information is
+saved."
=C2=A0 =C2=A0:type '(repeat sexp)
=C2=A0 =C2=A0:group 'ibuffer)

=C2=A0(defvar ibuffer-hidden-filter-groups nil
-=C2=A0 "A list of filtering groups which are currently hidden.")=
+=C2=A0 "The list of filter groups that are currently hidden.")
=C2=A0(defvar ibuffer-filter-group-kill-ring nil)

@@ -602,18 +658,38 @@ print

=C2=A0;;;###autoload
=C2=A0(defun ibuffer-included-in-filters-p (buf filters)
+=C2=A0 "Return non-nil if BUF passes all FILTERS.
+
+BUF is a lisp buffer object, and FILTERS is a list of filter
+specifications with the same structure as
+`ibuffer-filtering-qualifiers'."
=C2=A0 =C2=A0(not
=C2=A0 =C2=A0 (memq nil ;; a filter will return nil if it failed
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (mapcar
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; filter should be like (TYPE . QUALIFI= ER), or
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; (or (TYPE . QUALIFIER) (TYPE . QUALIF= IER) ...)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0#'(lambda (qual)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(ibuffer-included-in-filte= r-p buf qual))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0filters))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (mapcar #'(lambda (filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(ibuffer-included-in-filter-p buf filter))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0filters))))<= br> +
+(defun ibuffer-unary-operand (filter)
+=C2=A0 "Extracts operand from a unary compound FILTER specification.<= br> +
+FILTER should be a cons cell of either form (f . d) or (f d),
+where operand d is itself a cons cell, or nil. Returns d."
+=C2=A0 (let* ((tail (cdr filter))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(maybe-q (car-safe tail)))
+=C2=A0 =C2=A0 (if (consp maybe-q) maybe-q tail)))

=C2=A0(defun ibuffer-included-in-filter-p (buf filter)
+=C2=A0 "Return non-nil if BUF pass FILTER.
+
+BUF is a lisp buffer object, and FILTER is a filter
+specification, with the same structure as an element of the list
+`ibuffer-filtering-qualifiers'."
=C2=A0 =C2=A0(if (eq (car filter) 'not)
-=C2=A0 =C2=A0 =C2=A0 (not (ibuffer-included-in-filter-p-1 buf (cdr fi= lter)))
+=C2=A0 =C2=A0 =C2=A0 (let ((inner (ibuffer-unary-operand filter)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; Allows (not (not ...)) etc, which may be ov= erkill
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (if (eq (car inner) 'not)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-included-in-filter-p bu= f (ibuffer-unary-operand inner))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (ibuffer-included-in-filter-p-1 buf inner))))
=C2=A0 =C2=A0 =C2=A0(ibuffer-included-in-filter-p-1 buf filter)))

=C2=A0(defun ibuffer-included-in-filter-p-1 (buf filter)
@@ -621,9 +697,19 @@ ibuffer-included-in-filter-p-1
=C2=A0 =C2=A0 (not
=C2=A0 =C2=A0 =C2=A0(pcase (car filter)
=C2=A0 =C2=A0 =C2=A0 =C2=A0(`or
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;;; ATTN: Short-circuiting alternative with par= allel structure w/`and
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;;(catch 'has-match
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 (dolist (filter-spec (cdr filter) nil)=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 (when (ibuffer-included-in-filt= er-p buf filter-spec)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 (throw 'has-match t)= )))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (memq t (mapcar #'(lambda (x)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 (ibuffer-included-in-filter-p buf x))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (cdr filter))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0(ibuffer-included-in-filter-p buf x))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cdr filter))))
+=C2=A0 =C2=A0 =C2=A0 (`and
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(catch 'no-match
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(dolist (filter-spec (cdr filter) t)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(unless (ibuffer-included-in-filt= er-p buf filter-spec)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(throw 'no-match nil))= )))
=C2=A0 =C2=A0 =C2=A0 =C2=A0(`saved
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((data (assoc (cdr= filter) ibuffer-saved-filters)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(unless data
@@ -916,17 +1002,17 @@ ibuffer-pop-filter
=C2=A0 =C2=A0 =C2=A0(when buf
=C2=A0 =C2=A0 =C2=A0 =C2=A0(ibuffer-jump-to-buffer (buffer-name buf)))))
-(defun ibuffer-push-filter (qualifier)
-=C2=A0 "Add QUALIFIER to `ibuffer-filtering-qualifiers'.&quo= t;
-=C2=A0 (push qualifier ibuffer-filtering-qualifiers))
+(defun ibuffer-push-filter (filter-specification)
+=C2=A0 "Add FILTER-SPECIFICATION to `ibuffer-filtering-qualifiers'= ;."
+=C2=A0 (push filter-specification ibuffer-filtering-qualifiers))

=C2=A0;;;###autoload
=C2=A0(defun ibuffer-decompose-filter ()
-=C2=A0 "Separate the top compound filter (OR, NOT, or SAVED) in this = buffer.
+=C2=A0 "Separate this buffer's top compound filter (AND, OR, NOT,= or SAVED).

=C2=A0This means that the topmost filter on the filtering stack, which must=
=C2=A0be a complex filter like (OR [name: foo] [mode: bar-mode]), will be -turned into two separate filters [name: foo] and [mode: bar-mode]." +turned into separate filters, like [name: foo] and [mode: bar-mode]."=
=C2=A0 =C2=A0(interactive)
=C2=A0 =C2=A0(unless ibuffer-filtering-qualifiers
=C2=A0 =C2=A0 =C2=A0(error "No filters in effect"= ;))
@@ -935,14 +1021,14 @@ ibuffer-decompose-filter
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (tail (cdr filters))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (value
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(pcase (caar filters)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (`or (nconc head tail))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((or `or 'and) (nconc head t= ail))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(`saved
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((data (assoc head ib= uffer-saved-filters)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless data
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-fil= ter-disable)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (error "= ;Unknown saved filter %s" head))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (append (cdr data) = tail)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (`not (cons head tail))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (`not (cons (ibuffer-unary-opera= nd (car filters)) tail))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(_
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (error "Filter type %= s is not compound" (caar filters))))))
=C2=A0 =C2=A0 =C2=A0(setq ibuffer-filtering-qualifiers value))
@@ -971,31 +1057,36 @@ ibuffer-negate-filter
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering= -qualifiers))
=C2=A0 =C2=A0(ibuffer-update nil t))

+(defun ibuffer--or-and-filter (op decompose)
+=C2=A0 (if decompose
+=C2=A0 =C2=A0 =C2=A0 (if (eq op (caar ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (error "Top filter is not an %s" (up= case (symbol-name op))))
+=C2=A0 =C2=A0 (when (< (length ibuffer-filtering-qualifiers) 2)
+=C2=A0 =C2=A0 =C2=A0 (error "Need two filters to %s" (upcase (sy= mbol-name op))))
+=C2=A0 =C2=A0 ;; If either filter is an op, eliminate unnecessary nesting.=
+=C2=A0 =C2=A0 (let ((first (pop ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (second (pop ibuffer-filtering-qualifie= rs)))
+=C2=A0 =C2=A0 =C2=A0 (push (nconc (if (eq op (car first)) first (list op f= irst))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(if (= eq op (car second)) (cdr second) (list second)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)))
+=C2=A0 (ibuffer-update nil t))
+
=C2=A0;;;###autoload
-(defun ibuffer-or-filter (&optional reverse)
+(defun ibuffer-or-filter (&optional decompose)
=C2=A0 =C2=A0"Replace the top two filters in this buffer with their lo= gical OR.
-If optional argument REVERSE is non-nil, instead break the top OR
+If optional argument DECOMPOSE is non-nil, instead break the top OR
=C2=A0filter into parts."
=C2=A0 =C2=A0(interactive "P")
-=C2=A0 (if reverse
-=C2=A0 =C2=A0 =C2=A0 (progn
-=C2=A0 =C2=A0 =C2=A0 =C2=A0(when (or (null ibuffer-filtering-qualifiers) -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (eq = 9;or (caar ibuffer-filtering-qualifiers))))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(error "Top filter is not an OR&quo= t;))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((lim (pop ibuffer-filtering-qualifiers))<= wbr>)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq ibuffer-filtering-qualifiers
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(nconc (cdr lim) ib= uffer-filtering-qualifiers))))
-=C2=A0 =C2=A0 (when (< (length ibuffer-filtering-qualifiers) 2)
-=C2=A0 =C2=A0 =C2=A0 (error "Need two filters to OR"))
-=C2=A0 =C2=A0 ;; If the second filter is an OR, just add to it.
-=C2=A0 =C2=A0 (let ((first (pop ibuffer-filtering-qualifiers))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(second (pop ibuffer-filtering-qualifier= s)))
-=C2=A0 =C2=A0 =C2=A0 (if (eq 'or (car second))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(push (nconc (list 'or first) (cdr s= econd))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filtering-q= ualifiers)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0(push (list 'or first second)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filtering-qualifie= rs))))
-=C2=A0 (ibuffer-update nil t))
+=C2=A0 (ibuffer--or-and-filter 'or decompose))
+
+;;;###autoload
+(defun ibuffer-and-filter (&optional decompose)
+=C2=A0 "Replace the top two filters in this buffer with their logical= AND.
+If optional argument DECOMPOSE is non-nil, instead break the top AND
+filter into parts."
+=C2=A0 (interactive "P")
+=C2=A0 (ibuffer--or-and-filter 'and decompose))

=C2=A0(defun ibuffer-maybe-save-stuff ()
=C2=A0 =C2=A0(when ibuffer-save-with-custom
@@ -1069,7 +1160,9 @@ ibuffer-format-filter-group-data

=C2=A0(defun ibuffer-format-qualifier (qualifier)
=C2=A0 =C2=A0(if (eq (car-safe qualifier) 'not)
-=C2=A0 =C2=A0 =C2=A0 (concat " [NOT" (ibuffer-format-qualifier-1= (cdr qualifier)) "]")
+=C2=A0 =C2=A0 =C2=A0 (concat " [NOT"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-format-qualifier= -1 (ibuffer-unary-operand qualifier))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "]")
=C2=A0 =C2=A0 =C2=A0(ibuffer-format-qualifier-1 qualifier)))

=C2=A0(defun ibuffer-format-qualifier-1 (qualifier)
@@ -1078,14 +1171,16 @@ ibuffer-format-qualifier-1
=C2=A0 =C2=A0 =C2=A0 (concat " [filter: " (cdr q= ualifier) "]"))
=C2=A0 =C2=A0 =C2=A0(`or
=C2=A0 =C2=A0 =C2=A0 (concat " [OR" (mapconcat #'ibuffer-form= at-qualifier
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cdr qualifier) "") "]"= ))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cdr qualifier) "") "]= "))
+=C2=A0 =C2=A0 (`and
+=C2=A0 =C2=A0 =C2=A0(concat " [AND" (mapconcat #'ibuffer-for= mat-qualifier
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cdr qualifier) "") "= ]"))
=C2=A0 =C2=A0 =C2=A0(_
=C2=A0 =C2=A0 =C2=A0 (let ((type (assq (car qualifier) ibuffer-filtering-al= ist)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless qualifier
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (error "Ibuffer: bad qualifier %s" q= ualifier))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(error "Ibuffer: bad qualifier %s&q= uot; qualifier))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (concat " [" (cadr type) ": &quo= t; (format "%s]" (cdr qualifier)))))))

-
=C2=A0(defun ibuffer-list-buffer-modes (&optional include-parents)
=C2=A0 =C2=A0"Create a completion table of buffer modes currently in u= se.
=C2=A0If INCLUDE-PARENTS is non-nil then include parent modes."
@@ -1103,7 +1198,7 @@ ibuffer-list-buffer-modes

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext&q= uot;)
=C2=A0(define-ibuffer-filter mode
-=C2=A0 "Toggle current view to buffers with major mode QUALIFIER.&quo= t;
+=C2=A0 "Limit current view to buffers with major mode QUALIFIER."= ;
=C2=A0 =C2=A0(:description "major mode"
=C2=A0 =C2=A0 :reader
=C2=A0 =C2=A0 (let* ((buf (ibuffer-current-buffer))
@@ -1123,7 +1218,7 @@ mode

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-= ext")
=C2=A0(define-ibuffer-filter used-mode
-=C2=A0 "Toggle current view to buffers with major mode QUALIFIER.
+=C2=A0 "Limit current view to buffers with major mode QUALIFIER.
=C2=A0Called interactively, this function allows selection of modes
=C2=A0currently used by buffers."
=C2=A0 =C2=A0(:description "major mode in use"
@@ -1142,7 +1237,7 @@ used-mode

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-derived-mode &qu= ot;ibuf-ext")
=C2=A0(define-ibuffer-filter derived-mode
-=C2=A0 =C2=A0 "Toggle current view to buffers whose major mode inheri= ts from QUALIFIER."
+=C2=A0 =C2=A0 "Limit current view to buffers whose major mode inherit= s from QUALIFIER."
=C2=A0 =C2=A0(:description "derived mode"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :reader
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (intern
@@ -1153,22 +1248,74 @@ derived-mode

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-name "ibuf-ext&q= uot;)
=C2=A0(define-ibuffer-filter name
-=C2=A0 "Toggle current view to buffers with name matching QUALIFIER.&= quot;
+=C2=A0 "Limit current view to buffers with name matching QUALIFIER.&q= uot;
=C2=A0 =C2=A0(:description "buffer name"
=C2=A0 =C2=A0 :reader (read-from-minibuffer "Filter by name (regexp): = "))
=C2=A0 =C2=A0(string-match qualifier (buffer-name buf)))

+;;;###autoload (autoload 'ibuffer-filter-by-starred-name "ib= uf-ext")
+(define-ibuffer-filter starred-name
+=C2=A0 =C2=A0 "Limit current view to buffers with name beginning and = ending
+with *, along with an optional suffix of the form digits or
+<digits>."
+=C2=A0 (:description "starred buffer name"
+=C2=A0 =C2=A0:reader nil)
+=C2=A0 (ignore qualifier)
+=C2=A0 (string-match "\\`\\*[^*]+\\*\\(?:<[[:digit:]]+>\\)= ?\\'" (buffer-name buf)))
+
=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-filename "ibuf-e= xt")
=C2=A0(define-ibuffer-filter filename
-=C2=A0 "Toggle current view to buffers with filename matching QUALIFI= ER."
-=C2=A0 (:description "filename"
-=C2=A0 =C2=A0:reader (read-from-minibuffer "Filter by filename (regex= p): "))
+=C2=A0 =C2=A0 "Limit current view to buffers with full file na= me matching QUALIFIER.
+
+For example, for a buffer associated with file '/a/b/c.d', this +matches against '/a/b/c.d'."
+=C2=A0 (:description "full file name"
+=C2=A0 =C2=A0:reader (read-from-minibuffer "Filter by full file name = (regexp): "))
=C2=A0 =C2=A0(ibuffer-awhen (with-current-buffer buf (ibuf= fer-buffer-file-name))
=C2=A0 =C2=A0 =C2=A0(string-match qualifier it)))

+;;;###autoload (autoload 'ibuffer-filter= -by-basename "ibuf-ext")
+(define-ibuffer-filter basename
+=C2=A0 =C2=A0 "Limit current view to buffers with file basename match= ing QUALIFIER.
+
+For example, for a buffer associated with file '/a/b/c.d', this +matches against 'c.d'."
+=C2=A0 (:description "file basename"
+=C2=A0 =C2=A0:reader (read-from-minibuffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Filter by file name, witho= ut directory part (regex): "))
+=C2=A0 (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name))=
+=C2=A0 =C2=A0 (string-match qualifier (file-name-nondirectory it))))
+
+;;;###autoload (autoload 'ibuffer-filter-by-file-extension "= ibuf-ext")
+(define-ibuffer-filter file-extension
+=C2=A0 =C2=A0 "Limit current view to buffers with filename extension = matching QUALIFIER.
+
+The separator character (typically `.') is not part of the
+pattern. For example, for a buffer associated with file
+'/a/b/c.d', this matches against 'd'."
+=C2=A0 (:description "filename extension"
+=C2=A0 =C2=A0:reader (read-from-minibuffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Filter by filename extensi= on without separator (regex): "))
+=C2=A0 (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name))=
+=C2=A0 =C2=A0 (string-match qualifier (or (file-name-extension it) "&= quot;))))
+
+;;;###autoload (autoload 'ibuffer-filter-by-directory "ibuf-ext&q= uot;)
+(define-ibuffer-filter directory
+=C2=A0 =C2=A0 "Limit current view to buffers with directory matching = QUALIFIER.
+
+For a buffer associated with file '/a/b/c.d', this matches
+against '/a/b'. For a buffer not associated with a file, this
+matches against the value of `default-directory' in that buffer."=
+=C2=A0 (:description "directory name"
+=C2=A0 =C2=A0:reader (read-from-minibuffer "Filter by directory name = (regex): "))
+=C2=A0 (ibuffer-aif (with-current-buffer buf (ibuffer-buffer-file-name)) +=C2=A0 =C2=A0 =C2=A0 (let ((dirname (file-name-directory it)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when dirname (string-match qualifier dirname)= ))
+=C2=A0 =C2=A0 (when default-directory (string-match qualifier default-dire= ctory))))
+
=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-size-gt=C2=A0 "i= buf-ext")
=C2=A0(define-ibuffer-filter size-gt
-=C2=A0 "Toggle current view to buffers with size greater than QUALIFI= ER."
+=C2=A0 "Limit current view to buffers with size greater than QUALIFIE= R."
=C2=A0 =C2=A0(:description "size greater than"
=C2=A0 =C2=A0 :reader
=C2=A0 =C2=A0 (string-to-number (read-from-minibuffer "Filter by size = greater than: ")))
@@ -1177,16 +1324,32 @@ size-gt

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-size-lt=C2=A0 "i= buf-ext")
=C2=A0(define-ibuffer-filter size-lt
-=C2=A0 =C2=A0"Toggle current view to buffers with size less than QUAL= IFIER."
+=C2=A0 =C2=A0 "Limit current view to buffers with size less than QUAL= IFIER."
=C2=A0 =C2=A0(:description "size less than"
=C2=A0 =C2=A0 :reader
=C2=A0 =C2=A0 (string-to-number (read-from-minibuffer "Filter by size = less than: ")))
=C2=A0 =C2=A0(< (with-current-buffer buf (buffer-size))
=C2=A0 =C2=A0 =C2=A0 qualifier))

+;;;###autoload (autoload 'ibuffer-filter-by-modified "ibuf-ext&qu= ot;)
+(define-ibuffer-filter modified
+=C2=A0 =C2=A0 "Limit current view to buffers that are marked as modif= ied."
+=C2=A0 (:description "modified"
+=C2=A0 =C2=A0:reader nil)
+=C2=A0 (ignore qualifier)
+=C2=A0 (buffer-modified-p buf))
+
+;;;###autoload (autoload 'ibuffer-filter-by-visiting-file "i= buf-ext")
+(define-ibuffer-filter visiting-file
+=C2=A0 =C2=A0 "Limit current view to buffers that are visiting a file= ."
+=C2=A0 (:description "visiting a file"
+=C2=A0 =C2=A0:reader nil)
+=C2=A0 (ignore qualifier)
+=C2=A0 (with-current-buffer buf (buffer-file-name)))
+
=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-content "ibuf-ex= t")
=C2=A0(define-ibuffer-filter content
-=C2=A0 =C2=A0"Toggle current view to buffers whose contents match QUA= LIFIER."
+=C2=A0 =C2=A0"Limit current view to buffers whose contents match QUAL= IFIER."
=C2=A0 =C2=A0(:description "content"
=C2=A0 =C2=A0 :reader (read-from-minibuffer "Filter by content (regexp= ): "))
=C2=A0 =C2=A0(with-current-buffer buf
@@ -1196,12 +1359,33 @@ content

=C2=A0;;;###autoload (autoload 'ibuffer-filter-by-predicate "ibuf-= ext")
=C2=A0(define-ibuffer-filter predicate
-=C2=A0 =C2=A0"Toggle current view to buffers for which QUALIFIER retu= rns non-nil."
+=C2=A0 =C2=A0"Limit current view to buffers for which QUALIFIER retur= ns non-nil."
=C2=A0 =C2=A0(:description "predicate"
=C2=A0 =C2=A0 :reader (read-minibuffer "Filter by predicate (form): &q= uot;))
=C2=A0 =C2=A0(with-current-buffer buf
=C2=A0 =C2=A0 =C2=A0(eval qualifier)))

+;;;###autoload (autoload 'ibuffer-filter-chosen-by-completion &qu= ot;ibuf-ext")
+(defun ibuffer-filter-chosen-by-completion ()
+=C2=A0 "Select and apply filter chosen by completion against availabl= e filters.
+Indicates corresponding key sequences in echo area after filtering.
+
+The completion matches against the filter description text of
+each filter in `ibuffer-filtering-alist'."
+=C2=A0 (interactive)
+=C2=A0 (let* ((filters (mapcar (lambda (x) (cons (cadr x) (car x)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 ibuffer-filtering-alist))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(match (completing-read "Filter by:= " filters nil t))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(filter (cdr (assoc match filters)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(command (intern (concat "ibuffer-f= ilter-by-" (symbol-name filter)))))
+=C2=A0 =C2=A0 (call-interactively command)
+=C2=A0 =C2=A0 (message "%s can be run with key sequences: %s" +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0command
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mapconcat #'key-descr= iption
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (where-is-internal command ibuffer-mode-map nil t)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 "or "))))
+
+
=C2=A0;;; Sorting

=C2=A0;;;###autoload
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 94cee32..5a74084 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -518,26 +518,37 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "s f") 'ibuffer-do-s= ort-by-filename/process)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "s m") 'ibuffer-do-s= ort-by-major-mode)

+=C2=A0 =C2=A0 (define-key map (kbd "/ RET") 'ibuffer-filter-= by-mode)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ m") 'ibuffer-filt= er-by-used-mode)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ M") 'ibuffer-filt= er-by-derived-mode)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ n") 'ibuffer-filt= er-by-name)
-=C2=A0 =C2=A0 (define-key map (kbd "/ c") 'ibuffer-filter-by= -content)
-=C2=A0 =C2=A0 (define-key map (kbd "/ e") 'ibuffer-filter-by= -predicate)
+=C2=A0 =C2=A0 (define-key map (kbd "/ *") 'ibuffer-filter-by= -starred-name)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ f") 'ibuffer-filt= er-by-filename)
-=C2=A0 =C2=A0 (define-key map (kbd "/ >") 'ibuffer-filter= -by-size-gt)
+=C2=A0 =C2=A0 (define-key map (kbd "/ b") 'ibuffer-filter-by= -basename)
+=C2=A0 =C2=A0 (define-key map (kbd "/ .") 'ibuffer-filter-by= -file-extension)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ <") 'ibuffer-f= ilter-by-size-lt)
+=C2=A0 =C2=A0 (define-key map (kbd "/ >") 'ibuffer-filter= -by-size-gt)
+=C2=A0 =C2=A0 (define-key map (kbd "/ i") 'ibuffer-filter-by= -modified)
+=C2=A0 =C2=A0 (define-key map (kbd "/ v") 'ibuffer-filter-by= -visiting-file)
+=C2=A0 =C2=A0 (define-key map (kbd "/ c") 'ibuffer-filter-by= -content)
+=C2=A0 =C2=A0 (define-key map (kbd "/ e") 'ibuffer-filter-by= -predicate)
+
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ r") 'ibuffer-swit= ch-to-saved-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ a") 'ibuffer-add-= saved-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ x") 'ibuffer-dele= te-saved-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ d") 'ibuffer-deco= mpose-filter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ s") 'ibuffer-save= -filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ p") 'ibuffer-pop-= filter)
+=C2=A0 =C2=A0 (define-key map (kbd "/ <up>") 'ibuffer-= pop-filter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ !") 'ibuffer-nega= te-filter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ t") 'ibuffer-exch= ange-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ TAB") 'ibuffer-ex= change-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ o") 'ibuffer-or-f= ilter)
+=C2=A0 =C2=A0 (define-key map (kbd "/ |") 'ibuffer-or-filter= )
+=C2=A0 =C2=A0 (define-key map (kbd "/ &") 'ibuffer-and-f= ilter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ g") 'ibuffer-filt= ers-to-filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ P") 'ibuffer-pop-= filter-group)
+=C2=A0 =C2=A0 (define-key map (kbd "/ S-<up>") 'ibuffe= r-pop-filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ D") 'ibuffer-deco= mpose-filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ /") 'ibuffer-filt= er-disable)

@@ -657,13 +668,43 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0ibuffer-filter-by-derived-mode))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter filter-by-n= ame]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "Add filter by buffer name.= .." ibuffer-filter-by-name))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-starre= d-name]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by starred buffer na= me..."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-fil= ter-by-starred-name
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help "= ;List buffers whose names begin with a star"))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter filter-by-f= ilename]
-=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by filename..."= ibuffer-filter-by-filename))
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by full filename...&= quot; ibuffer-filter-by-filename
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (concat &qu= ot;For a buffer associated with file '/a/b/c.d', "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 "list buffer if a given pattern matches '/a/b/c.= d'")))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-basena= me]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by file basename...&= quot;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-fil= ter-by-basename
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help (conc= at "For a buffer associated with file '/a/b/c.d', "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "list buffer if a given pattern= matches 'c.d'")))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-file-e= xtension]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by file name extensi= on..."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-fil= ter-by-file-extension
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help (conc= at "For a buffer associated with file '/a/b/c.d', "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "list buffer if a given pattern= matches 'd'")))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-direct= ory]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by filename's di= rectory..."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-fil= ter-by-directory
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (concat &qu= ot;For a buffer associated with file '/a/b/c.d', "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 "list buffer if a given pattern matches '/a/b= 9;")))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter filter-by-s= ize-lt]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "Add filter by size less th= an..." ibuffer-filter-by-size-lt))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter filter-by-s= ize-gt]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "Add filter by size greater= than..."
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filter-by-size-gt))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-modifi= ed]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by modified buffer&q= uot; ibuffer-filter-by-modified
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help "= ;List buffers that are marked as modified"))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view filter filter-by-visiti= ng-file]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "Add filter by buffer visiting a= file"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-fil= ter-by-visiting-file
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :help "= ;List buffers that are visiting files"))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter filter-by-c= ontent]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "Add filter by content (reg= exp)..."
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filter-by-content))
@@ -673,6 +714,12 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view f= ilter pop-filter]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "Remove top filter" ib= uffer-pop-filter
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:enable (and (featurep 'ibuf-ext) ibu= ffer-filtering-qualifiers)))
+=C2=A0 =C2=A0 (define-key-after map [menu-bar view= filter and-filter]
+=C2=A0 =C2=A0 =C2=A0 '(menu-item "AND top two filters" ibuff= er-and-filter
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 :enable (and (featurep 'ibuf-ext) ibuffer-= filtering-qualifiers
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(cdr ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 :help
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "Create a new filter which is the logical= AND of the top two filters"))
=C2=A0 =C2=A0 =C2=A0(define-key-after map [menu-bar view filter or-f= ilter]
=C2=A0 =C2=A0 =C2=A0 =C2=A0'(menu-item "OR top two filters" i= buffer-or-filter
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:enable (and (featurep &= #39;ibuf-ext) ibuffer-filtering-qualifiers
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el=
index 92ed101..40760ab 100644
--- a/test/lisp/ibuffer-tests.el
+++ b/test/lisp/ibuffer-tests.el
@@ -24,7 +24,8 @@
=C2=A0 =C2=A0(require 'ibuf-macs))

=C2=A0(ert-deftest ibuffer-autoload ()
-=C2=A0 "Tests to see whether reftex-auc has been autoloaded"
+=C2=A0 "Tests to see whether ibuffer has been autoloaded"
+=C2=A0 (skip-unless (not (featurep 'ibuf-ext)))
=C2=A0 =C2=A0(should
=C2=A0 =C2=A0 (fboundp 'ibuffer-mark-unsaved-buffers))
=C2=A0 =C2=A0(should
@@ -138,5 +139,669 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(should-not ibuffer-filtering-qual= ifiers))
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq ibuffer-filtering-qualifiers filters))))

+;; Test Filter Inclusion
+(let* (test-buffer-list=C2=A0 ; accumulated buffers to clean up
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;; Utility functions without polluting the envi= ronment
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(set-buffer-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (buffer mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Set BUFFER's major mode to MO= DE, a mode function, or fundamental."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer buffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall (or mode #'fundamen= tal-mode)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(set-buffer-contents
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (buffer size include-content)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Add exactly SIZE bytes to BUFFER,= including INCLUDE-CONTENT."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (or size include-content)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((unit "\n")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(chun= k "ccccccccccccccccccccccccccccccc\n")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(chun= k-size (length chunk))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size= (if (and size include-content (stringp include-content))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(- size (length include-content))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0size)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless (or (null size) (= > size 0))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (error "size = argument must be nil or positive"))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer buff= er
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when include-cont= ent
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (insert inc= lude-content))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when size
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (dotimes (_= (floor size chunk-size))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ins= ert chunk))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (dotimes (_= (mod size chunk-size))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ins= ert unit)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; prevent query o= n cleanup
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (set-buffer-modifi= ed-p nil))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(create-file-buffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (prefix &rest args-plist)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Create a file and buffer with des= ignated properties.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 PREFIX is a string giving the beginning of the= name, and ARGS-PLIST
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 is a series of keyword-value pairs, with allow= ed keywords
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 :suffix STRING, :size NUMBER, :mode MODE-FUNC,= :include-content STRING.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Returns the created buffer."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((suffix=C2=A0 (plist-get args-pl= ist :suffix))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size=C2=A0 = =C2=A0 (plist-get args-plist :size))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(include (pl= ist-get args-plist :include-content))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mode=C2=A0 = =C2=A0 (plist-get args-plist :mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(file=C2=A0 = =C2=A0 (make-temp-file prefix nil suffix))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(buf=C2=A0 = =C2=A0 =C2=A0(find-file-noselect file t)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push buf test-buffer-list) ; re= cord for cleanup
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall set-buffer-mode buf mod= e)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall set-buffer-contents buf= size include)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 buf)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(create-non-file-buffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda (prefix &rest args-plist)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Create a non-file and buffer with= designated properties.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 PREFIX is a string giving the beginning of the= name, and ARGS-PLIST
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 is a series of keyword-value pairs, with allow= ed keywords
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 :size NUMBER, :mode MODE-FUNC, :include-conten= t STRING.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Returns the created buffer."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((size=C2=A0 =C2=A0 (plist-get ar= gs-plist :size))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(include (pl= ist-get args-plist :include-content))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mode=C2=A0 = =C2=A0 (plist-get args-plist :mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(buf=C2=A0 = =C2=A0 =C2=A0(generate-new-buffer prefix)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push buf test-buffer-list) ; re= cord for cleanup
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall set-buffer-mode buf mod= e)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall set-buffer-contents buf= size include)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 buf)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(clean-up
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda ()
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Restore all emacs state modified = during the tests"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (while test-buffer-list=C2=A0 =C2=A0 = =C2=A0 =C2=A0; created temporary buffers
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf (pop test-buffer-list= )))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer buf = (bury-buffer)) ; ensure not selected
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (kill-buffer buf)))))) +=C2=A0 ;; Tests
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-1 ()
+=C2=A0 =C2=A0 "Tests inclusion using basic filter combinators with a = single buffer."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-fil= e-buffer "ibuf-test-1" :size 100
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :include-content "One ring to rule them all\n")))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((size-gt . 99))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((size-lt . 101))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((mode . fundamental-mode))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((content . "ring to rule them all"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (content . "ring to rule them all")))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (and (content . "ring to rule them all"))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (and (and (content . "ring to rule them all")))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((or (content . "ring to rule them all")))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (not (content . "ring to rule them all"))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (size-gt . 99)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (content . "ring to rule them all"= ;)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (mode . fundamental-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (basename . "\\`ibuf-test-1")))))=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (or (not (size-gt . 99))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (content . "ring to= rule them all"))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode . fundamental-mode= ))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (basename . "\\`ibu= f-test-1")))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (or (size-gt . 99) (size-lt . 10))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and (content . "ring.*all")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(content . "rule&q= uot;)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(content . "them a= ll")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(content . "One&qu= ot;))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode . text-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (basename . "\\`ibuf-test-1")))))= )
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-2 ()
+=C2=A0 =C2=A0 "Tests inclusion of basic filters in combination on a s= ingle buffer."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-fil= e-buffer "ibuf-test-2" :size 200
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'text-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :include-content "and in the darkness find them\n")))<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((size-gt . 199))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((size-lt . 201))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((not size-gt . 200))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((not (size-gt . 200)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (size-gt . 199) (size-lt . 201)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((or (size-gt . 199) (size-gt . 201)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((or (size-gt . 201) (size-gt . 199)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((size-gt . 199) (mode . text-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(content . "darkness find them"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (size-gt . 199) (mode . text-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (content . "darkness find them"))= )))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (or (not (size-gt . 199)) (not (mode . text-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (content . "darknes= s find them")))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((or (size-gt . 200) (content . "darkness find them")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(derived-mode . emacs-lisp-mode)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0buf '((or (size-gt . 200) (content . "rule them all"= ;)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(derived-mode . emacs-lisp-mod= e))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-3 ()
+=C2=A0 =C2=A0 "Tests inclusion with filename filters on specified buf= fers."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((bufA
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall create-fi= le-buffer "ibuf-test-3.a" :size 50
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0:mode #'text-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0:include-content "...but a multitude of drops?\n"= ;))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(bufB
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (funcall create-no= n-file-buffer "ibuf-test-3.b" :size 50
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0:mode #'text-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0:include-content "...but a multitude of drops?\n"= ;))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(dirA (with-current= -buffer bufA default-directory))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(dirB (with-current= -buffer bufB default-directory)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = '((basename . "ibuf-test-3"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = '((basename . "test-3\\.a"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = '((file-extension . "a"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = (list (cons 'directory dirA))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0bufB '((basename . "ibuf-test-3"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0bufB '((file-extension . "b"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufB = (list (cons 'directory dirB))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = '((name . "ibuf-test-3"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufB = '((name . "ibuf-test-3")))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-4 ()
+=C2=A0 =C2=A0 "Tests inclusion with various filters on a single buffe= r."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-fil= e-buffer "ibuf-test-4"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'emacs-lisp-mode :suffix ".el"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :include-content "(message \"--%s--\" 'emacs-= rocks)\n")))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((file-extension . "el"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((derived-mode . prog-mode))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((used-mode . emacs-lisp-mode))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((mode . emacs-lisp-mode))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer buf (set-buffer-mo= dified-p t))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((modified))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer buf (set-buffer-mo= dified-p nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((not modified))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (file-extension . "el")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (derived-mode . prog-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not modified)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((or (file-extension . "tex")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(derived-mode . prog-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modified)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((file-extension . "el")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(derived-mode . prog-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(not modified)))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-5 ()
+=C2=A0 =C2=A0 "Tests inclusion with various filters on a single buffe= r."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-non= -file-buffer "ibuf-test-5.el"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'emacs-lisp-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :include-content
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 "(message \"--%s--\" \"It really does!\"= ;)\n")))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0buf '((file-extension . "el"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((size-gt . 18))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((predicate . (lambda ()
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (> (-= (point-max) (point-min)) 18))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (mode . emacs-lisp-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (or (starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (size-gt . 18))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and (not (size-gt . 100))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(content . "[Ii]t= =C2=A0 *really does!")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(or (name . "test-= 5")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (fil= ename . "test-5")))))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-6 ()
+=C2=A0 =C2=A0 "Tests inclusion using saved filters and DeMorgan's= laws."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-non= -file-buffer "*ibuf-test-6*" :size 65
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'text-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (buf2
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-fil= e-buffer "ibuf-test-6a" :suffix ".html"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'html-mode
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :include-content
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 "<HTML><BODY><H1>Hello, World!</H1>= </BODY></HTML>")))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf '((starred-name))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0buf '((saved . "text document"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p = buf2 '((saved . "web"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf2 = '((not (and (not (derived-mode . sgml-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (derived-mode . c= ss-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0. javascript-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0. js2-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0. scss-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (derived-mode . h= aml-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (not (mode=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0. sass-mode)))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((and (starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (or (size-gt . 50) (filename . "foo&qu= ot;))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (or (not starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and (size-lt . 51)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (fil= ename . "foo")))))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-7 ()
+=C2=A0 =C2=A0 "Tests inclusion with various filters on a single buffe= r."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-non= -file-buffer "ibuf-test-7"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'artist-mode)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (starred-name)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not starred-name))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (not (not starred-name))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (modified)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not modified))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf &= #39;((not (not (not modified)))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-filter-inclusion-8 ()
+=C2=A0 =C2=A0 "Tests inclusion with various filters."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((bufA
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall create-non= -file-buffer "ibuf-test-8a"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 :mode #'artist-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bufB (funcall create-non= -file-buffer "*ibuf-test-8b*" :size 32))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bufC (funcall create-fil= e-buffer "ibuf-test8c" :suffix "*"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:size 64))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bufD (funcall create-fil= e-buffer "*ibuf-test8d" :size 128))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bufE (funcall create-fil= e-buffer "*ibuf-test8e" :suffix "*<2>"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:size 16))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bufF (and (funcall creat= e-non-file-buffer "*ibuf-test8f*")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(funcall create-non-file-buffer "*ibuf-test8f*"<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :size 8))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer bufA (set-buffer-m= odified-p t))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufA = '((and (not starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(modified)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "test-8")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (size-gt . 100))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mode . picture-mode)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer bufA (set-buffer-m= odified-p nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-not (ibuffer-included-in-filter= s-p
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0bufA '((or (starred-name) (visiting-file) (modified)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufB = '((and (starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "test.*8b")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-gt . 31)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not visiting-file)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufC = '((and (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(visiting-file)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "8c[^*]*\\*")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-lt . 65)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufD = '((and (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(visiting-file)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "\\`\\*.*test8d") +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-lt . 129)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-gt . 127)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufE = '((and (starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(visiting-file)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "8e.*?\\*<[[:digit:]]= +>")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-gt . 10)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (ibuffer-included-in-filters-p<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bufF = '((and (starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (visiting-file))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "8f\\*<[[:digit:]]>= ;")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(size-lt . 10))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up))))
+
+;; Test Filter Combination and Decomposition
+(let* (ibuffer-to-kill=C2=A0 =C2=A0 =C2=A0 =C2=A0; if non-nil, kill this b= uffer at cleanup
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(ibuffer-already 'check) ; existing ibuffer= buffer to use but not kill
+=C2=A0 =C2=A0 =C2=A0 =C2=A0;; Utility functions without polluting the envi= ronment
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(get-test-ibuffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda ()
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Returns a test ibuffer-mode buffe= r, creating one if necessary.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 If a new buffer is created, it is named=C2=A0 = \"*Test-Ibuffer*\" and is
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 saved to `ibuffer-to-kill' for later clean= up."
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (eq ibuffer-already 'check) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-already
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (catch '= ;found-buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (dol= ist (buf (buffer-list) nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (when (with-current-buffer buf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (derived-mode-p 'ibuffer-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (throw 'found-buf buf))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (or ibuffer-already
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-to-kill
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((test-ibuf-name &qu= ot;*Test-Ibuffer*"))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer nil test-= ibuf-name nil t)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-to-k= ill (get-buffer test-ibuf-name))))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(clean-up
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (lambda ()
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Restore all emacs state modified = during the tests"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when ibuffer-to-kill=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0; created ibuffer
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer ibuffer-to-= kill
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (set-buffer-modified-p ni= l)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (bury-buffer))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (kill-buffer ibuffer-to-kill) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-to-kill nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and ibuffer-already (not (eq ibu= ffer-already 'check)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; restore existing ibuffer stat= e
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-update nil t)))))
+=C2=A0 ;; Tests
+=C2=A0 (ert-deftest ibuffer-decompose-filter ()
+=C2=A0 =C2=A0 "Tests `ibuffer-decompose-filter' for and, or, not,= and saved."
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuf (funcall get-test-ibuffer)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer ibuf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuffer-filtering-qualifi= ers nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-fi= lter-groups nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (filters &#= 39;((size-gt . 100) (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(name . "foo"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (cons 'o= r filters) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal fil= ters ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (cons 'a= nd filters) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal fil= ters ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (list 'n= ot (car filters)) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal (li= st (car filters))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (cons 'n= ot (car filters)) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal (li= st (car filters))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((gnus (assoc "= gnus" ibuffer-saved-filters)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push '(saved = . "gnus") ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal (cd= r gnus) ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-decompose= -filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (equal (cd= r (cadr gnus)) ibuffer-filtering-qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (not (assoc "_= _unknown__" ibuffer-saved-filters))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push '(saved = . "__uknown__") ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibu= ffer-decompose-filter) :type 'error)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (car filters= ) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibu= ffer-decompose-filter) :type 'error)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq ibuffer-filt= ering-qualifiers nil)))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-and-filter ()
+=C2=A0 =C2=A0 "Tests `ibuffer-and-filter' in an Ibuffer buffer.&q= uot;
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuf (funcall get-test-ibuffer)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer ibuf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuffer-filtering-qualifi= ers nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-fi= lter-groups nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (filters [(= size-gt . 100) (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (filename . "A") (mode . text-mode)])) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibuffer-an= d-filter) :type 'error)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (aref filter= s 1) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibu= ffer-and-filter) :type 'error))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (aref filters 0) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'and (aref filters 0) (aref filters 1)) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter 'decompose)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(equal (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null ibuffer-filtering-qualifiers))))<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'and (aref filters 0) (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'and (aref filters 0) (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'or (aref filters 2)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 3)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'and (list 'or (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-and-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'and
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'or (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'or (aref filters 2)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 3)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers))))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up)))
+
+=C2=A0 (ert-deftest ibuffer-or-filter ()
+=C2=A0 =C2=A0 "Tests `ibuffer-or-filter' in an Ibuffer buffer.&qu= ot;
+=C2=A0 =C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 =C2=A0 (unwind-protect
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuf (funcall get-test-ibuffer)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (with-current-buffer ibuf
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((ibuffer-filtering-qualifi= ers nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (ibuffer-fi= lter-groups nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (filters [(= size-gt . 100) (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (filename . "A") (mode . text-mode)])) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibuffer-or= -filter) :type 'error)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (push (aref filter= s 1) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should-error (ibu= ffer-or-filter) :type 'error))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (aref filters 0) ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'or (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter 'decompose)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(equal (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null ibuffer-filtering-qualifiers))))<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'or (aref filters 0) (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'or (aref filters 0) (aref filters 1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'and (aref filters 2)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 3)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'or (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'or (list 'and (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers)))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (pop ibuffer-filtering-qu= alifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (should (progn
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 2) (aref filters 3))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (push (list 'and (aref filters 0) (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ibuffer-filtering-qualifiers)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (ibuffer-or-filter)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (and (equal (list 'or
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'and (aref filters 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 1))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= list 'and (aref filters 2)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (aref filters 3)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car ibuffer-filtering= -qualifiers))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(null (cdr ibuffer-filtering-qualifiers))))))))
+=C2=A0 =C2=A0 =C2=A0 (funcall clean-up))))
+
+(ert-deftest ibuffer-format-qualifier ()
+=C2=A0 "Tests string recommendation of filter from `ibuffer-format-qu= alifier'."
+=C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 (let ((test1 '(mode . org-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (test2 '(size-lt . 100))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (test3 '(derived-mode . prog-mode))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (test4 '(or (size-gt . 10000)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and= (not (starred-name))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(directory . "\\<org\\>"))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (test5 '(or (filename . "scratch"= ;)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (fil= ename . "bonz")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (fil= ename . "temp")))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (test6 '(or (mode . emacs-lisp-mode) (file= -extension . "elc?")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and= (starred-name) (name . "elisp"))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (mod= e . lisp-interaction-mode)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (description (lambda (q)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cadr (assq q ibuffer-filtering-alist))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (tag (lambda (&rest args )
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(concat " [&qu= ot; (apply #'concat args) "]"))))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test1)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag (funcall description 'mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 ": " "org-mode")))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test2)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag (funcall description 'size-lt)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 ": " "100")))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test3)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag (funcall description 'derived-mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 ": " "prog-mode")))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test4)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag "OR"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'size-gt) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " (= format "%s" 10000))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag "AND"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall tag &qu= ot;NOT"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (funcall tag
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall description
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 'starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " "nil&qu= ot;))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall tag
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (funcall description 'directory)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 ": " "\\<org\\>")))))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test5)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag "OR"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'filename) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": "= =C2=A0 "scratch")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'filename) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " &= quot;bonz")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'filename) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " &= quot;temp"))))
+=C2=A0 =C2=A0 (should (equal (ibuffer-format-qualifier test6)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(func= all tag "OR"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " &= quot;emacs-lisp-mode")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'file-extens= ion)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " &= quot;elc?")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag "AND"
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall tag
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (funcall description 'starred-name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 ": " "nil")
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall tag
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (funcall description 'name)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 ": " "elisp"))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (funcall tag (funcall description 'mode)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0": " &= quot;lisp-interaction-mode"))))))
+
+(ert-deftest ibuffer-unary-operand ()
+=C2=A0 "Tests `ibuffer-unary-operand': (not cell) or (not . cell)= -> cell."
+=C2=A0 (skip-unless (featurep 'ibuf-ext))
+=C2=A0 (should (equal (ibuffer-unary-operand '(not . (mode "foo&q= uot;)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'(mode &= quot;foo")))
+=C2=A0 (should (equal (ibuffer-unary-operand '(not (mode "foo&quo= t;)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'(mode &= quot;foo")))
+=C2=A0 (should (equal (ibuffer-unary-operand '(not "cdr")) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'("= cdr")))
+=C2=A0 (should (equal (ibuffer-unary-operand '(not)) nil))
+=C2=A0 (should (equal (ibuffer-unary-operand '(not . a)) 'a)))
+
=C2=A0(provide 'ibuffer-tests)
=C2=A0;; ibuffer-tests.el ends here
--
2.10.2

From 268f9de4ee4ef6cdba9d4c313a52e42653a1067c Mon Sep 17 0= 0:00:00 2001
From: Christopher Genovese <genovese= @cmu.edu>
Date: Fri, 9 Dec 2016 09:13:36 +0900
Subject: [PATCH 2/2] ibuffer: Update key bindings

* lisp/ibuffer.el (ibuffer-mode-map): Bind 'ibuffer-filter-by-directory= '
and 'ibuffer-filter-chosen-by-completion' to '//' and = '/TAB' respectively.
Rebind 'ibuffer-filter-disable' to '/ DEL'.
; * etc/NEWS: Update NEWS entries.
---
=C2=A0etc/NEWS=C2=A0 =C2=A0 =C2=A0 =C2=A0 | 10 ++++++----
=C2=A0lisp/ibuffer.el |=C2=A0 5 +++--
=C2=A02 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index f60deb1..fc2dfe5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -324,12 +324,14 @@ to '/b', '/.', '//', '/*&= #39;, '/i' and '/v'.

=C2=A0---
=C2=A0*** Two new commands 'ibuffer-filter-chosen-by-completion= 9;
-and `ibuffer-and-filter', the second bound to '/&'.
+and `ibuffer-and-filter'; bound to '/ TAB' and '/&'= ;
+respectively.

=C2=A0---
-*** The commands `ibuffer-pop-filter', `ibuffer-pop-filter-group',=
-`ibuffer-or-filter' and `ibuffer-filter-disable' have the alternat= ive
-bindings '/<up>', '/S-<up>', '/|' and = '/DEL', respectively.
+*** The key binding for `ibuffer-filter-disable' has being changed
+to '/DEL'; the commands `ibuffer-pop-filter', `ibuffer-pop-fil= ter-group'
+and `ibuffer-or-filter' have the alternative bindings '/<up>= ', '/S-<up>'
+and '/|'.

=C2=A0---
=C2=A0*** The data format specifying filters has been extended to allow
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 5a74084..db9cfeb 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -526,12 +526,14 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ f") 'ibuffer-filt= er-by-filename)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ b") 'ibuffer-filt= er-by-basename)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ .") 'ibuffer-filt= er-by-file-extension)
+=C2=A0 =C2=A0 (define-key map (kbd "/ /") 'ibuffer-filter-by= -directory)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ <") 'ibuffer-f= ilter-by-size-lt)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ >") 'ibuffer-f= ilter-by-size-gt)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ i") 'ibuffer-filt= er-by-modified)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ v") 'ibuffer-filt= er-by-visiting-file)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ c") 'ibuffer-filt= er-by-content)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ e") 'ibuffer-filt= er-by-predicate)
+=C2=A0 =C2=A0 (define-key map (kbd "/ TAB") 'ibuffer-filter-= chosen-by-completion)

=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ r") 'ibuffer-swit= ch-to-saved-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ a") 'ibuffer-add-= saved-filters)
@@ -542,7 +544,6 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ <up>") 'ibu= ffer-pop-filter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ !") 'ibuffer-nega= te-filter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ t") 'ibuffer-exch= ange-filters)
-=C2=A0 =C2=A0 (define-key map (kbd "/ TAB") 'ibuffer-exchang= e-filters)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ o") 'ibuffer-or-f= ilter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ |") 'ibuffer-or-f= ilter)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ &") 'ibuffer-= and-filter)
@@ -550,7 +551,7 @@ ibuffer-mode-map
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ P") 'ibuffer-pop-= filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ S-<up>") 'i= buffer-pop-filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "/ D") 'ibuffer-deco= mpose-filter-group)
-=C2=A0 =C2=A0 (define-key map (kbd "/ /") 'ibuffer-filter-di= sable)
+=C2=A0 =C2=A0 (define-key map (kbd "/ DEL") 'ibuffer-filter-= disable)

=C2=A0 =C2=A0 =C2=A0(define-key map (kbd "M-n") 'ibuffer-forw= ard-filter-group)
=C2=A0 =C2=A0 =C2=A0(define-key map "\t" 'ibuffer-forward-fil= ter-group)
--
2.10.2


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;;;;;;;;;;
In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.4)
=C2=A0of 2016-12-08
Repository revision: f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1

--94eb2c088ee26e61870543a39d65--