From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#54374: 29.0.50; previous-completion fails at beginning of completions buffer Date: Tue, 24 May 2022 22:12:27 +0300 Organization: LINKOV.NET Message-ID: <861qwiu4rd.fsf@mail.linkov.net> References: <86h782b3zk.fsf@mail.linkov.net> <871qz5k2na.fsf@posteo.net> <86bky99c7r.fsf@mail.linkov.net> <87fsnk39nr.fsf@posteo.net> <86k0cwlcge.fsf@mail.linkov.net> <875yobnd7n.fsf@posteo.net> <864k3tu4pp.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="20768"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (x86_64-pc-linux-gnu) Cc: 54374@debbugs.gnu.org To: Philip Kaludercic Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue May 24 21:29:40 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 1ntaDr-0005HF-RD for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 24 May 2022 21:29:39 +0200 Original-Received: from localhost ([::1]:60406 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ntaDq-0006UN-RL for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 24 May 2022 15:29:38 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:42068) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ntZzi-0007dh-6t for bug-gnu-emacs@gnu.org; Tue, 24 May 2022 15:15:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:59546) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ntZzh-0000Zp-Tz for bug-gnu-emacs@gnu.org; Tue, 24 May 2022 15:15:01 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1ntZzh-00055K-Pi for bug-gnu-emacs@gnu.org; Tue, 24 May 2022 15:15:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 24 May 2022 19:15:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54374 X-GNU-PR-Package: emacs Original-Received: via spool by 54374-submit@debbugs.gnu.org id=B54374.165341967619499 (code B ref 54374); Tue, 24 May 2022 19:15:01 +0000 Original-Received: (at 54374) by debbugs.gnu.org; 24 May 2022 19:14:36 +0000 Original-Received: from localhost ([127.0.0.1]:53443 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ntZzH-00054Q-Kb for submit@debbugs.gnu.org; Tue, 24 May 2022 15:14:36 -0400 Original-Received: from relay10.mail.gandi.net ([217.70.178.230]:41407) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ntZzD-00053z-Qy for 54374@debbugs.gnu.org; Tue, 24 May 2022 15:14:32 -0400 Original-Received: (Authenticated sender: juri@linkov.net) by mail.gandi.net (Postfix) with ESMTPSA id D59EA240003; Tue, 24 May 2022 19:14:24 +0000 (UTC) In-Reply-To: <864k3tu4pp.fsf@mail.linkov.net> (Juri Linkov's message of "Sat, 19 Mar 2022 21:13:14 +0200") 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: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:233027 Archived-At: --=-=-= Content-Type: text/plain >>> Thanks, this fixed the issue. And I noticed another one: at the >>> beginning of the buffer previous-completion wraps to the end of the buffer, >>> not to the beginning of the last completion. >>> >>> Also when point at the last completion, next-completion >>> jumps to the end of the buffer instead of wrapping to the >>> first completion. >> >> I cannot replicate this issue in every case, but only if the last option >> has completion annotation. It should be fixable by checking for these >> kinds of edge-cases, but it might also be better to reconsider if >> next-completion should be using `mouse-face' for navigation, or if a >> special text property might be more elegant? > > I agree that `mouse-face' is unsuitable for detecting the completion > boundaries, and it causes other problems: typing RET on the completion prefix > or on the completion suffix/annotation causes the error: > > Debugger entered--Lisp error: (error "No completion here") > error("No completion here") > choose-completion(13 nil) > funcall-interactively(choose-completion 13 nil) > command-execute(choose-completion) > > So a special text property could also help to detect the completion for RET, > if there are no such text properties already. But I see there is the > text property 'completion--string'. So maybe it could be extended to cover > prefix and suffix/annotation as well. Here is the patch that fixes 4 bugs: 2 bugs described above, and also bug#55289 and bug#55430. --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=first-completion.patch diff --git a/lisp/ido.el b/lisp/ido.el index e5717d6e53..73cd163d46 100644 --- a/lisp/ido.el +++ b/lisp/ido.el @@ -3939,7 +3939,7 @@ ido-switch-to-completions ;; In the new buffer, go to the first completion. ;; FIXME: Perhaps this should be done in `ido-completion-help'. (when (bobp) - (next-completion 1))))) + (first-completion))))) (defun ido-completion-auto-help () "Call `ido-completion-help' if `completion-auto-help' is non-nil." diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 8287007d32..8948d16949 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2070,11 +2151,11 @@ completion--insert (when prefix (let ((beg (point)) (end (progn (insert prefix) (point)))) - (put-text-property beg end 'mouse-face nil))) + (add-text-properties beg end `(mouse-face nil completion--string ,(car str))))) (completion--insert (car str) group-fun) (let ((beg (point)) (end (progn (insert suffix) (point)))) - (put-text-property beg end 'mouse-face nil) + (add-text-properties beg end `(mouse-face nil completion--string ,(car str))) ;; Put the predefined face only when suffix ;; is added via annotation-function without prefix, ;; and when the caller doesn't use own face. diff --git a/lisp/simple.el b/lisp/simple.el index 1efd900030..75b548aea6 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -9523,6 +9523,20 @@ completion-auto-select :version "29.1" :group 'completion) +(defun first-completion () + (interactive) + (goto-char (point-min)) + (unless (get-text-property (point) 'completion--string) + (let ((next (next-single-property-change (point) 'completion--string))) + (when next (goto-char next))))) + +(defun last-completion () + (interactive) + (goto-char (point-max)) + (unless (get-text-property (point) 'completion--string) + (let ((prev (previous-single-property-change (point) 'completion--string))) + (when prev (goto-char prev))))) + (defun previous-completion (n) "Move to the previous item in the completion list. With prefix argument N, move back N items (negative N means move @@ -9539,14 +9553,6 @@ next-completion Also see the `completion-wrap-movement' variable." (interactive "p") - (let ((prev (previous-single-property-change (point) 'mouse-face))) - (goto-char (cond - ((not prev) - (1- (next-single-property-change (point) 'mouse-face))) - ((/= prev (point)) - (point)) - (t prev)))) - (let ((beg (point-min)) (end (point-max)) (tabcommand (member (this-command-keys) '("\t" [backtab]))) @@ -9554,44 +9560,43 @@ next-completion (catch 'bound (while (> n 0) ;; If in a completion, move to the end of it. - (when (get-text-property (point) 'mouse-face) - (goto-char (next-single-property-change (point) 'mouse-face nil end))) + (when (get-text-property (point) 'completion--string) + (goto-char (next-single-property-change (point) 'completion--string nil end))) ;; If at the last completion option, wrap or skip to the - ;; minibuffer, if requested. We can't use (eobp) because some - ;; extra text may be after the last candidate: ex: when - ;; completion-detailed - (setq prop (next-single-property-change (point) 'mouse-face nil end)) + ;; minibuffer, if requested. + (setq prop (next-single-property-change (point) 'completion--string nil end)) (when (and completion-wrap-movement (eq end prop)) (if (and completion-auto-select tabcommand) (throw 'bound nil) (goto-char (point-min)))) ;; Move to start of next one. - (unless (get-text-property (point) 'mouse-face) - (goto-char (next-single-property-change (point) 'mouse-face nil end))) + (unless (get-text-property (point) 'completion--string) + (goto-char (next-single-property-change (point) 'completion--string nil end))) (setq n (1- n))) - (while (and (< n 0) (not (bobp))) - (setq prop (get-text-property (1- (point)) 'mouse-face)) + (while (< n 0) + (unless (bobp) + (setq prop (get-text-property (1- (point)) 'completion--string))) ;; If in a completion, move to the start of it. - (when (and prop (eq prop (get-text-property (point) 'mouse-face))) + (when (and prop (eq prop (get-text-property (point) 'completion--string))) (goto-char (previous-single-property-change - (point) 'mouse-face nil beg))) + (point) 'completion--string nil beg))) ;; Move to end of the previous completion. - (unless (or (bobp) (get-text-property (1- (point)) 'mouse-face)) + (unless (or (bobp) (get-text-property (1- (point)) 'completion--string)) (goto-char (previous-single-property-change - (point) 'mouse-face nil beg))) + (point) 'completion--string nil beg))) ;; If at the first completion option, wrap or skip to the ;; minibuffer, if requested. - (setq prop (previous-single-property-change (point) 'mouse-face nil beg)) + (setq prop (previous-single-property-change (point) 'completion--string nil beg)) (when (and completion-wrap-movement (eq beg prop)) (if (and completion-auto-select tabcommand) (progn - (goto-char (next-single-property-change (point) 'mouse-face nil end)) + (goto-char (next-single-property-change (point) 'completion--string nil end)) (throw 'bound nil)) (goto-char (point-max)))) ;; Move to the start of that one. (goto-char (previous-single-property-change - (point) 'mouse-face nil beg)) + (point) 'completion--string nil beg)) (setq n (1+ n)))) (when (/= 0 n) (switch-to-minibuffer)))) @@ -9620,13 +9625,14 @@ choose-completion (goto-char (posn-point (event-start event))) (let (beg) (cond - ((and (not (eobp)) (get-text-property (point) 'mouse-face)) + ((and (not (eobp)) (get-text-property (point) 'completion--string)) (setq beg (1+ (point)))) ((and (not (bobp)) - (get-text-property (1- (point)) 'mouse-face)) + (get-text-property (1- (point)) 'completion--string)) (setq beg (point))) (t (error "No completion here"))) - (setq beg (previous-single-property-change beg 'mouse-face)) + (setq beg (or (previous-single-property-change beg 'completion--string) + beg)) (substring-no-properties (get-text-property beg 'completion--string)))))) @@ -9832,8 +9838,8 @@ switch-to-completions ((and (memq this-command '(completion-at-point minibuffer-complete)) (equal (this-command-keys) [backtab])) (goto-char (point-max)) - (previous-completion 1)) - (t (next-completion 1)))))) + (last-completion)) + (t (first-completion)))))) (defun read-expression-switch-to-completions () "Select the completion list window while reading an expression." --=-=-=--