From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: sbaugh@catern.com Newsgroups: gmane.emacs.devel Subject: Re: Updating *Completions* as you type Date: Sun, 19 Nov 2023 19:22:49 +0000 (UTC) Message-ID: <87il5xlf9b.fsf@catern.com> References: <87bkd3z9bi.fsf@catern.com> <86cyxjyr1y.fsf@mail.linkov.net> <ier34ye4a3x.fsf@janestreet.com> <86r0lxm7um.fsf@mail.linkov.net> <87sf6dx954.fsf@catern.com> <87ttqpwea9.fsf@catern.com> <86wmvlw178.fsf@mail.linkov.net> <87bkcwx3ft.fsf@catern.com> <86y1g076vh.fsf@mail.linkov.net> <87sf68unh1.fsf@catern.com> <86zg0fu99i.fsf@mail.linkov.net> <875y33v73h.fsf@catern.com> <87y1fztke8.fsf@catern.com> <86r0lrw17x.fsf@mail.linkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="4068"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-devel@gnu.org To: Juri Linkov <juri@linkov.net> Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Nov 19 20:23:42 2023 Return-path: <emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org> Envelope-to: ged-emacs-devel@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 <emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org>) id 1r4nOP-0000um-4P for ged-emacs-devel@m.gmane-mx.org; Sun, 19 Nov 2023 20:23:41 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <emacs-devel-bounces@gnu.org>) id 1r4nNf-0006M2-Vo; Sun, 19 Nov 2023 14:22:56 -0500 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 <bounces+21787432-489d-emacs-devel=gnu.org@em8926.catern.com>) id 1r4nNd-0006LY-FL for emacs-devel@gnu.org; Sun, 19 Nov 2023 14:22:53 -0500 Original-Received: from s.wrqvtbkv.outbound-mail.sendgrid.net ([149.72.123.24]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <bounces+21787432-489d-emacs-devel=gnu.org@em8926.catern.com>) id 1r4nNb-0001nI-G8 for emacs-devel@gnu.org; Sun, 19 Nov 2023 14:22:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=catern.com; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: cc:content-type:from:subject:to; s=s1; bh=2zmGQ7TKlwdXK5SG1NOx7sIV9o61k6p0YNIVFcyigaE=; b=hfm9kKkKcrgE+oeh2IVU+W8ThirdCq+bFo67xw5ZqfIVWBFFIuDFFTyJvGS/lEDalfnM HKupPBSUUUHL6xk3EgMOlldbDvRexvXFapvFNSEOXmFjFA8jB7x0JWzXsWQnYwkY+AavsL SfqCSkUSImC/yFtvt528+3l1GEuVROmvzK8D/HYluJvmZx/m15CphcQPY6kyLCaZTjZ2yo jd0q3esdLOyZkXSPoD9whlV9q7dwCwfqk6frZ823bE2DgvCu5TY0SXSdZ9mIitEJpHtfO3 gqi309NS0G2E3nhHCzt5ZlgeGYKw/8ACk+BA3BGOtj+3FTJwnedbZ5rPMFveQ0Tg== Original-Received: by filterdrecv-5bbdbb56cd-hwvxf with SMTP id filterdrecv-5bbdbb56cd-hwvxf-1-655A6089-18 2023-11-19 19:22:49.894934106 +0000 UTC m=+2853779.109916393 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-39 (SG) with ESMTP id KYRKrsE5SZyqZKj4IZLY5Q Sun, 19 Nov 2023 19:22:49.781 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=74.101.51.129; helo=localhost; envelope-from=sbaugh@catern.com; receiver=linkov.net Original-Received: from localhost (unknown [74.101.51.129]) by earth.catern.com (Postfix) with ESMTPSA id 937B062E41; Sun, 19 Nov 2023 19:22:40 +0000 (UTC) In-Reply-To: <86r0lrw17x.fsf@mail.linkov.net> (Juri Linkov's message of "Thu, 19 Oct 2023 09:55:14 +0300") X-SG-EID: =?us-ascii?Q?ZgbRq7gjGrt0q=2FPjvxk7wM0yQFRdOkTJAtEbkjCkHbKN0eTXXiSaHma0yVkCMW?= =?us-ascii?Q?9xk7Netwyshu=2FmcYqvvXaa4RWD9mhBUzGzYxYRD?= =?us-ascii?Q?LbTnalf3=2F8Iww2FBtepsXK2tfgJwL54of3Ttma7?= =?us-ascii?Q?tdLawmAE94l1sjeC60tFDat1LcPp4A6GR4qsaWC?= =?us-ascii?Q?fktfkphYNhX6wfUMIV3RSsYhNq4dEYwIM4Q=3D=3D?= X-Entity-ID: d/0VcHixlS0t7iB1YKCv4Q== Received-SPF: pass client-ip=149.72.123.24; envelope-from=bounces+21787432-489d-emacs-devel=gnu.org@em8926.catern.com; helo=s.wrqvtbkv.outbound-mail.sendgrid.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." <emacs-devel.gnu.org> List-Unsubscribe: <https://lists.gnu.org/mailman/options/emacs-devel>, <mailto:emacs-devel-request@gnu.org?subject=unsubscribe> List-Archive: <https://lists.gnu.org/archive/html/emacs-devel> List-Post: <mailto:emacs-devel@gnu.org> List-Help: <mailto:emacs-devel-request@gnu.org?subject=help> List-Subscribe: <https://lists.gnu.org/mailman/listinfo/emacs-devel>, <mailto:emacs-devel-request@gnu.org?subject=subscribe> Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:313014 Archived-At: <http://permalink.gmane.org/gmane.emacs.devel/313014> --=-=-= Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Juri Linkov <juri@linkov.net> writes: >> How about this? > > Looks good. > >> + (read-buffer-sort minibuffer >> + (choice (const :tag "completions-sort controls sorting" nil) >> + (const :tag "sort matching buffer-list" buffer-list)) >> + "30.1") > > Shouldn't 'read-buffer-sort' support other choices from 'completions-sort'? > Your new choice 'historical' would sort buffers by the order of 'M-p' > the same way as 'buffer-list' will sort buffers by the order of 'M-n'. > Also 'alphabetical' would be useful for 'C-x b' when 'completions-sort' > was customized to something else. Finally got to it, I've added that in this patch (which combines both the read-buffer-sort and completions-sort changes). The nice reusable part is that the new minibuffer-sort-by-history and minibuffer-sort-alphabetically should work for any completion table. So it will be easy to just add options for different completion tables, e.g. read-file-name-sort, and they can just use those pre-existing functions. This does require adding the new dynamic variable minibuffer-completion-base which maybe should go in some other place, or could be derived from some other variable - I'm not sure. Possibly it's fine as I did it. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Add-read-buffer-sort-to-customize-how-read-buffer-so.patch >From 5e898c3ef323971af89b80fe37d94be0bf29443f Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Tue, 17 Oct 2023 09:09:55 -0400 Subject: [PATCH] Add read-buffer-sort to customize how read-buffer sorts completions Add the ability to customize how read-buffer (actually internal-complete-buffer) sorts the buffer completion candidates. Also add minibuffer-sort-alphabetically and minibuffer-sort-by-history to provide some reasonable options for read-buffer-sort. And add support for them to completions-sort, too, as a simple change. * lisp/minibuffer.el (completions-sort): Document 'historical option. (minibuffer-completion-help): Support 'historical option. (minibuffer-sort-alphabetically) (minibuffer-completion-base, minibuffer-sort-by-history): Add. * lisp/cus-start.el (standard): Add customization information for read-buffer-sort. * src/minibuf.c (Finternal_complete_buffer): Use read-buffer-sort. (syms_of_minibuf): Add read-buffer-sort. --- lisp/cus-start.el | 7 ++++++ lisp/minibuffer.el | 63 +++++++++++++++++++++++++++++++++++++++++----- src/minibuf.c | 32 ++++++++++++++++++++--- 3 files changed, 93 insertions(+), 9 deletions(-) diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 6d83aaf4d14..40bc4078d77 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -441,6 +441,13 @@ minibuffer-prompt-properties--setter (read-buffer-function minibuffer (choice (const nil) function)) + (read-buffer-sort minibuffer + (choice (const :tag "completions-sort controls sorting" nil) + (const :tag "sort matching buffer-list" buffer-list) + (const :tag "sort alphabetically" minibuffer-sort-alphabetically) + (const :tag "sort historically" minibuffer-sort-by-history) + (function :tag "User-defined function")) + "30.1") ;; msdos.c (dos-unsupported-char-glyph display integer) ;; nsterm.m diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 026613c9eb2..49086ff6eff 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1307,14 +1307,26 @@ completion-cycle-threshold (defcustom completions-sort 'alphabetical "Sort candidates in the *Completions* buffer. -The value can be nil to disable sorting, `alphabetical' for -alphabetical sorting or a custom sorting function. The sorting -function takes and returns a list of completion candidate -strings." +Candidate completions in the *Completions* are sorted depending +on the value. + +If nil, sorting is disabled. +If `alphabetical', candidates are sorted by +`minibuffer-sort-alphabetically'. +If `historical', candidates are sorted by +`minibuffer-sort-by-history'. +If a function, the function is called to sort the candidates. +The sorting function takes and returns a list of completion +candidate strings. + +If the completion-specific metadata provides a +`display-sort-function', that is used instead and this value is +ignored." :type '(choice (const :tag "No sorting" nil) (const :tag "Alphabetical sorting" alphabetical) + (const :tag "Historical sorting" historical) (function :tag "Custom function")) - :version "29.1") + :version "30.1") (defcustom completions-group nil "Enable grouping of completion candidates in the *Completions* buffer. @@ -1640,6 +1652,43 @@ minibuffer--sort-preprocess-history (substring c base-size))) hist))))) +(defun minibuffer-sort-alphabetically (completions) + "Sort COMPLETIONS alphabetically. + +COMPLETIONS are sorted alphabetically by `string-lessp'. + +This is a suitable function to use for `completions-sort' or to +include as `display-sort-function' in completion metadata." + (sort completions #'string-lessp)) + +(defvar minibuffer-completion-base nil + "The base for the current completion. + +This is the part of the current minibuffer input which is not +being completed on. This is primarily relevant for file names, +where this is the directory component of the file name.") + +(defun minibuffer-sort-by-history (completions) + "Sort COMPLETIONS by their position in `minibuffer-history-variable'. + +COMPLETIONS are sorted first by `minibuffer-sort-alphbetically', +then any elements occuring in the minibuffer history list are +moved to the front based on the order they occur in the history. +If a history variable hasn't been specified for this call of +`completing-read', COMPLETIONS are sorted only by +`minibuffer-sort-alphbetically'. + +This is a suitable function to use for `completions-sort' or to +include as `display-sort-function' in completion metadata." + (let ((alphabetized (sort completions #'string-lessp))) + ;; Only use history when it's specific to these completions. + (if (eq minibuffer-history-variable + (default-value minibuffer-history-variable)) + alphabetized + (minibuffer--sort-by-position + (minibuffer--sort-preprocess-history minibuffer-completion-base) + alphabetized)))) + (defun minibuffer--group-by (group-fun sort-fun elems) "Group ELEMS by GROUP-FUN and sort groups by SORT-FUN." (let ((groups)) @@ -2470,6 +2519,7 @@ minibuffer-completion-help (let* ((last (last completions)) (base-size (or (cdr last) 0)) (prefix (unless (zerop base-size) (substring string 0 base-size))) + (minibuffer-completion-base (substring string 0 base-size)) (base-prefix (buffer-substring (minibuffer--completion-prompt-end) (+ start base-size))) (base-suffix @@ -2540,7 +2590,8 @@ minibuffer-completion-help (funcall sort-fun completions) (pcase completions-sort ('nil completions) - ('alphabetical (sort completions #'string-lessp)) + ('alphabetical (minibuffer-sort-alphabetically completions)) + ('historical (minibuffer-sort-by-history completions)) (_ (funcall completions-sort completions))))) ;; After sorting, group the candidates using the diff --git a/src/minibuf.c b/src/minibuf.c index 58adde1bf66..04551afeb79 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -2186,9 +2186,15 @@ DEFUN ("internal-complete-buffer", Finternal_complete_buffer, Sinternal_complete else if (EQ (flag, Qlambda)) return Ftest_completion (string, Vbuffer_alist, predicate); else if (EQ (flag, Qmetadata)) - return list3 (Qmetadata, - Fcons (Qcategory, Qbuffer), - Fcons (Qcycle_sort_function, Qidentity)); + { + Lisp_Object res = list2 (Fcons (Qcategory, Qbuffer), + Fcons (Qcycle_sort_function, Qidentity)); + if (EQ (Vread_buffer_sort, Qbuffer_list)) + res = Fcons (Fcons (Qdisplay_sort_function, Qidentity), res); + else if (FUNCTIONP (Vread_buffer_sort)) + res = Fcons (Fcons (Qdisplay_sort_function, Vread_buffer_sort), res); + return Fcons (Qmetadata, res); + } else return Qnil; } @@ -2323,6 +2329,7 @@ syms_of_minibuf (void) DEFSYM (Qcase_fold_search, "case-fold-search"); DEFSYM (Qmetadata, "metadata"); DEFSYM (Qcycle_sort_function, "cycle-sort-function"); + DEFSYM (Qdisplay_sort_function, "display-sort-function"); /* A frame parameter. */ DEFSYM (Qminibuffer_exit, "minibuffer-exit"); @@ -2522,6 +2529,25 @@ syms_of_minibuf (void) the minibuffer. However, if `minibuffer-restore-windows' is present in `minibuffer-exit-hook', exiting the minibuffer will remove the window showing the *Completions* buffer, if any. */); + + DEFVAR_LISP ("read-buffer-sort", Vread_buffer_sort, + doc: /* Non-nil means sort completions in `read-buffer'. + +If this is nil (the default), completions in `read-buffer' are sorted +according to `completions-sort'. + +If this is `buffer-list', completions are sorted to match the order of +`buffer-list'. + +If a function, the function is called to sort the candidates. Some +possible values are `minibuffer-sort-alphabetically' and +`minibuffer-sort-by-history'. + +This variable only affects the default `read-buffer', so if +`read-buffer-function' is set to a function which does not use +`internal-complete-buffer', this variable will have no effect.*/); + Vread_buffer_sort = Qnil; + read_minibuffer_restore_windows = true; defsubr (&Sactive_minibuffer_window); -- 2.42.1 --=-=-=--