From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Philip Kaludercic Newsgroups: gmane.emacs.bugs Subject: bug#58839: [Patch] Re: bug#58839: 29.0.50; project-kill-buffer fails when Eglot is running Date: Tue, 01 Nov 2022 13:03:36 +0000 Message-ID: <877d0ehlnb.fsf@posteo.net> References: <87sfj8umwb.fsf@posteo.net> <213f3549-de4e-25a7-5e27-d13893e557bc@yandex.ru> <87zgdfwkle.fsf@gmail.com> <8e31a89d-e35e-6dd0-a8e3-f0b9684c8bfa@yandex.ru> <87v8o3wgq1.fsf@gmail.com> <87ilk2x1si.fsf@gmail.com> <871qqq7l9p.fsf@posteo.net> <87eduqwekz.fsf@gmail.com> <87wn8invbx.fsf@posteo.net> <877d0iw8iq.fsf@gmail.com> <837d0hhlke.fsf@gnu.org> <46ff0065-5645-ef1e-2621-242fb6a73f98@yandex.ru> <87v8o0uxn5.fsf@gmail.com> <787a4362-7ff5-7dbb-9118-16e4bee5f328@yandex.ru> <87edunvhf2.fsf@gmail.com> <6d4d9e72-1bae-4d64-b7c1-c2b9c11e396f@yandex.ru> <87tu3jgdbv.fsf@posteo.net> <87h6zihq3q.fsf@posteo.net> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36346"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Eli Zaretskii , manuel.uberti@inventati.org, 58839@debbugs.gnu.org, Dmitry Gutov To: =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Nov 01 14:34:33 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oprPV-0009BV-14 for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 01 Nov 2022 14:34:33 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1opqw1-000631-W3; Tue, 01 Nov 2022 09:04:06 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1opqvy-00062s-Cg for bug-gnu-emacs@gnu.org; Tue, 01 Nov 2022 09:04:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1opqvy-00050L-4r for bug-gnu-emacs@gnu.org; Tue, 01 Nov 2022 09:04:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1opqvx-0001cM-Rj for bug-gnu-emacs@gnu.org; Tue, 01 Nov 2022 09:04:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Philip Kaludercic Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 01 Nov 2022 13:04:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 58839 X-GNU-PR-Package: emacs Original-Received: via spool by 58839-submit@debbugs.gnu.org id=B58839.16673078336203 (code B ref 58839); Tue, 01 Nov 2022 13:04:01 +0000 Original-Received: (at 58839) by debbugs.gnu.org; 1 Nov 2022 13:03:53 +0000 Original-Received: from localhost ([127.0.0.1]:42934 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1opqvp-0001bz-7Y for submit@debbugs.gnu.org; Tue, 01 Nov 2022 09:03:53 -0400 Original-Received: from mout02.posteo.de ([185.67.36.66]:39715) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1opqvn-0001bi-32 for 58839@debbugs.gnu.org; Tue, 01 Nov 2022 09:03:51 -0400 Original-Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id 6CD3B240104 for <58839@debbugs.gnu.org>; Tue, 1 Nov 2022 14:03:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1667307825; bh=/222M8XfWI8uMFaf9WDWFktcmvGsyP2cVelny237lRU=; h=From:To:Cc:Subject:Autocrypt:Date:From; b=E2TirNsv46skA1FHUADAbVCehH3+GowHEc3IgecBBsBRlAgwpiVHInFf83hXdSCRU Pdbjy0DhTf5CL9f+bWgiGKQ8CpwN7NziYbNGFaRcGhLLHVxFwfVCUcyGpwlf3b21NC wfsKZ0spmwRZPvCAkj7Q3ywCOzQUrwLGkbD8h96KDK3ZKc9GpWgHDiR19WR2PZJVZP O00rBnV42RW3ejUds1wwOywhQfrBSGSfVWFLU7MPIo3NVYnQwUyb7GJuRrLtg6TCqq fwfpzaubSlij67mc+3daMkBnztBaldE4Vo0pfbEoft7B00LZQfcPPo70rvgE4AxMZF GKmtNvGbFldkw== Original-Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4N1qvy0VtNz9rxW; Tue, 1 Nov 2022 14:03:42 +0100 (CET) In-Reply-To: ("=?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?="'s message of "Tue, 1 Nov 2022 11:59:12 +0000") Autocrypt: addr=philipk@posteo.net; prefer-encrypt=nopreference; keydata= mDMEYHHqUhYJKwYBBAHaRw8BAQdAp3GdmYJ6tm5McweY6dEvIYIiry+Oz9rU4MH6NHWK0Ee0QlBo aWxpcCBLYWx1ZGVyY2ljIChnZW5lcmF0ZWQgYnkgYXV0b2NyeXB0LmVsKSA8cGhpbGlwa0Bwb3N0 ZW8ubmV0PoiQBBMWCAA4FiEEDM2H44ZoPt9Ms0eHtVrAHPRh1FwFAmBx6lICGwMFCwkIBwIGFQoJ CAsCBBYCAwECHgECF4AACgkQtVrAHPRh1FyTkgEAjlbGPxFchvMbxzAES3r8QLuZgCxeAXunM9gh io0ePtUBALVhh9G6wIoZhl0gUCbQpoN/UJHI08Gm1qDob5zDxnIHuDgEYHHqUhIKKwYBBAGXVQEF AQEHQNcRB+MUimTMqoxxMMUERpOR+Q4b1KgncDZkhrO2ql1tAwEIB4h4BBgWCAAgFiEEDM2H44Zo Pt9Ms0eHtVrAHPRh1FwFAmBx6lICGwwACgkQtVrAHPRh1Fw1JwD/Qo7kvtib8jy7puyWrSv0MeTS g8qIxgoRWJE/KKdkCLEA/jb9b9/g8nnX+UcwHf/4VfKsjExlnND3FrBviXUW6NcB X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: "bug-gnu-emacs" Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:246771 Archived-At: Jo=C3=A3o T=C3=A1vora writes: > On Tue, Nov 1, 2022 at 11:27 AM Philip Kaludercic > wrote: > > >> E.g. `display-buffer-alist' makes use of it to associate display-buffer >> rules with buffers. Now you can add >> >> ((major-mode . help-mode) display-buffer-in-side-window) >> >> instead of trying to match being a regular expression to catch all >> *Help* buffer names of a function along the lines of >> >> (lambda (buf _alist) >> (with-current-buffer buf >> (derived-mode-p 'help-mode))) >> > > If you really want to save up on this typing, it's better to define > a reusable helper function, or even a higher order function. > > (defun buffer-mode-matcher (mode) > (lambda (b _alist) > (with-current-buffer b (derived-mode-p 'help-mode)))) > > You can add buffer-mode-matcher to the library if it becomes > useful enough. Then you add: > > `(,(buffer-mode-matcher 'help-mode) display-buffer-in-side-window) > > to display-buffer-alist. > > But if you really want a new language your language, then I suggest > a simple adapter buffer-matcher utility that merges the two. That way one > doesn't couple existing utilities to the new mini-language and > simultaneously > the new mini-language become useful in a much wider setting for those who > appreciate such things. > > (defun buffer-matcher (condition) > "Return unary predicate of a buffer matching the CONDITION > mini-language." > (lambda (buf &rest _whatever) ; make it even more lax > (buffer-match-p condition))) > > Later on, you might even pass an (... &optional compiled) so that the > return value > is syntax checked and optimized in some way at compile time. > > IOW, (E)Lisp already gives you the tools for these composition without > needing to invent new languages with the drawbacks I listed. I was curious to try this out, and implemented something along the lines of your suggestion. The bad news is that it is at least 10 times slower than the current implementation, that isn't even really optimised. Perhaps I did something native and didn't see what is wrong, but here are my notes: --8<---------------cut here---------------start------------->8--- (defun translate-buffer-condition (condition) "Compile a CONDITION into a predicate function." (pcase-exhaustive condition ((or 't 'nil) (lambda (_buffer _arg) condition)) ((pred stringp) (lambda (buffer _arg) (string-match-p condition (buffer-name buffer)))) ((pred functionp) (if (eq 1 (cdr (func-arity condition))) (lambda (buffer _arg) (funcall condition buffer)) condition)) (`(major-mode . ,mode) (lambda (buffer _arg) (eq (buffer-local-value 'major-mode buffer) mode))) (`(derived-mode . ,mode) (lambda (buffer _arg) (provided-mode-derived-p (buffer-local-value 'major-mode buffer) mode))) (`(not . ,cond) (lambda (buffer arg) (not (funcall (translate-buffer-condition cond) buffer arg)))) (`(or . ,conds) (lambda (buffer arg) (catch 'match (dolist (cond conds) (when (funcall (translate-buffer-condition cond) buffer arg) (throw 'match t)))))) (`(and . ,conds) (lambda (buffer arg) (catch 'match (dolist (cond conds t) (when (funcall (translate-buffer-condition cond) buffer arg) (throw 'match nil)))))))) (defvar buffer-match-p-cache (make-hash-table :test 'eq)) (defun buffer-match-p/compiled (condition buffer-or-name &optional arg) "Return non-nil if BUFFER-OR-NAME matches CONDITION. CONDITION is either: - the symbol t, to always match, - the symbol nil, which never matches, - a regular expression, to match a buffer name, - a predicate function that takes a buffer object and ARG as arguments, and returns non-nil if the buffer matches, - a cons-cell, where the car describes how to interpret the cdr. The car can be one of the following: * `derived-mode': the buffer matches if the buffer's major mode is derived from the major mode in the cons-cell's cdr. * `major-mode': the buffer matches if the buffer's major mode is eq to the cons-cell's cdr. Prefer using `derived-mode' instead when both can work. * `not': the cdr is interpreted as a negation of a condition. * `and': the cdr is a list of recursive conditions, that all have to be met. * `or': the cdr is a list of recursive condition, of which at least one has to be met." (funcall (or (gethash condition buffer-match-p-cache) (puthash condition (byte-compile (translate-buffer-condition condition)) buffer-match-p-cache)) (get-buffer buffer-or-name) arg)) (defun match-buffers/compiled (condition &optional buffers arg) "Return a list of buffers that match CONDITION. See `buffer-match' for details on CONDITION. By default all buffers are checked, this can be restricted by passing an optional argument BUFFERS, set to a list of buffers to check. ARG is passed to `buffer-match', for predicate conditions in CONDITION." (let (bufs) (dolist (buf (or buffers (buffer-list))) (when (buffer-match-p/compiled condition (get-buffer buf) arg) (push buf bufs))) bufs)) ;; Here we will test a moderately complicated condition and time how ;; long it takes with the current implementation and with the proposed ;; alternative. (defvar sample-condition '(and (or buffer-file-name (derived-mode . compilation-mode) (derived-mode . dired-mode) (derived-mode . diff-mode) (derived-mode . comint-mode) (derived-mode . eshell-mode) (derived-mode . change-log-mode)) "\\*.+\\*" (not . "\\` "))) (benchmark-run 100 (match-buffers sample-condition pr)) ;; =3D> (1.7045469830000002 20 1.1418286690000023) (benchmark-run 1000 (match-buffers/compiled project-buffer-conditions pr)) ;; =3D> (17.646938126000002 219 12.428946030999999) --8<---------------cut here---------------end--------------->8--- I guess this just goes to show that one shouldn't underestimate the cost of a function call... LISP programmers know the value of everything and the cost of nothing. -- Alan Perlis=20