From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.devel Subject: Re: Wrong common substring highlighted in Completion buffer Date: Wed, 14 Dec 2005 09:59:09 +0200 Organization: JURTA Message-ID: <87zmn4qgqo.fsf@jurta.org> References: <87vexx1r63.fsf@jurta.org> <87oe3mopb6.fsf@jurta.org> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1134558584 8041 80.91.229.2 (14 Dec 2005 11:09:44 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Wed, 14 Dec 2005 11:09:44 +0000 (UTC) Cc: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Dec 14 12:09:42 2005 Return-path: Original-Received: from [199.232.75.2] (helo=lists.gnu.org) by ciao.gmane.org with esmtp (Exim 4.43) id 1EmUU2-0007zP-4Q for ged-emacs-devel@m.gmane.org; Wed, 14 Dec 2005 12:07:42 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EmUON-0004dV-Tm for ged-emacs-devel@m.gmane.org; Wed, 14 Dec 2005 06:01:52 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1EmS1o-0006au-7E for emacs-devel@gnu.org; Wed, 14 Dec 2005 03:30:25 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1EmS0k-0006BV-Mr for emacs-devel@gnu.org; Wed, 14 Dec 2005 03:29:26 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EmS0h-00069H-Q6 for emacs-devel@gnu.org; Wed, 14 Dec 2005 03:29:16 -0500 Original-Received: from [194.126.101.111] (helo=mail.neti.ee) by monty-python.gnu.org with esmtp (Exim 4.34) id 1EmS2g-00024v-Si; Wed, 14 Dec 2005 03:31:19 -0500 Original-Received: from mail.neti.ee (80-235-33-164-dsl.mus.estpak.ee [80.235.33.164]) by Relayhost1.neti.ee (Postfix) with ESMTP id 157611628; Wed, 14 Dec 2005 10:28:51 +0200 (EET) Original-To: rms@gnu.org In-Reply-To: (Richard M. Stallman's message of "Mon, 12 Dec 2005 22:15:13 -0500") User-Agent: Gnus/5.110004 (No Gnus v0.4) Emacs/22.0.50 (gnu/linux) X-Virus-Scanned: by amavisd-new-2.2.1 (20041222) (Debian) at neti.ee X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org X-Broken-Reverse-DNS: no host name found for IP address 199.232.75.2 Xref: news.gmane.org gmane.emacs.devel:47684 Archived-At: > If your fix needs fixing, please just do it. I hesitated to install this fix, because I felt this is not the right thing. Now I've completely reworked the function completion-setup-function and some related functions to make highlighting of common strings correct in many cases: * in normal minibuffer completion and in file name minibuffer completion; * for both above cases if point is at the end of the minibuffer and if point is in the middle of the minibuffer; * for partial-completion-mode with combinations of all cases above and with leading `-'; * for Info node/file completion (which uses completion-base-size-function); * for crm-minibuffer-completion (which reads multiple strings with completion). In the patch below the following changes were made: * Revert the change in display_completion_list_1 that explicitly uses minibuffer_completion_contents. Use nil as before. * Make the function minibuffer_completion_contents available to Lisp. Its Lisp name is minibuffer-completion-contents. * Use this function in completion-setup-function to get the correct completion part of the minibuffer. * Due to using this function in completion-setup-function, partial-completion-mode doesn't need to set the argument common-substring for display-completion-list. Completion-setup-function now does the right thing for it. There was one inconsistency in partial-completion-mode that needed special handling in completion-setup-function. I tracked it down to the dubious condition in `PC-do-completion': (equal (point) beg). This condition prevented point to be placed at the first different character in the minibuffer (as normal completion does) *if* this position is at the beginning of the minibuffer. After removing this condition this works consistently for the case of completions like `-function'. It puts point before `-function' and highlights the first character of available completions in the *Completions* buffer. So this change also removes the need for special handling of partial-completion-mode in completion-setup-function. * Another FIXME in completion-setup-function was saying about the need of an extra argument for completion-base-size-function. I replaced it with the advice to use the global value of completion-common-substring or directly the contents of the minibuffer in a function called via completion-base-size-function. Also I changed the lambda on Info-read-node-name-1 to match `(' on the global value of completion-common-substring or (minibuffer-completion-contents). Index: src/minibuf.c =================================================================== RCS file: /sources/emacs/emacs/src/minibuf.c,v retrieving revision 1.295 diff -c -r1.295 minibuf.c *** src/minibuf.c 11 Dec 2005 09:50:53 -0000 1.295 --- src/minibuf.c 14 Dec 2005 07:57:15 -0000 *************** *** 388,393 **** --- 388,406 ---- return make_buffer_string (prompt_end, ZV, 0); } + DEFUN ("minibuffer-completion-contents", Fminibuffer_completion_contents, + Sminibuffer_completion_contents, 0, 0, 0, + doc: /* Return the user input in a minibuffer before point as a string. + That is what completion commands operate on. + The current buffer must be a minibuffer. */) + () + { + int prompt_end = XINT (Fminibuffer_prompt_end ()); + if (PT < prompt_end) + error ("Cannot do completion in the prompt"); + return make_buffer_string (prompt_end, PT, 1); + } + DEFUN ("delete-minibuffer-contents", Fdelete_minibuffer_contents, Sdelete_minibuffer_contents, 0, 0, 0, doc: /* Delete all user input in a minibuffer. *************** *** 400,416 **** return Qnil; } - /* Get the text in the minibuffer before point. - That is what completion commands operate on. */ - - Lisp_Object - minibuffer_completion_contents () - { - int prompt_end = XINT (Fminibuffer_prompt_end ()); - if (PT < prompt_end) - error ("Cannot do completion in the prompt"); - return make_buffer_string (prompt_end, PT, 1); - } /* Read from the minibuffer using keymap MAP and initial contents INITIAL, putting point minus BACKUP_N bytes from the end of INITIAL, --- 413,418 ---- *************** *** 1899,1905 **** Lisp_Object last; struct gcpro gcpro1, gcpro2; ! completion = Ftry_completion (minibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate); last = last_exact_completion; --- 1904,1910 ---- Lisp_Object last; struct gcpro gcpro1, gcpro2; ! completion = Ftry_completion (Fminibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate); last = last_exact_completion; *************** *** 1921,1927 **** return 1; } ! string = minibuffer_completion_contents (); /* COMPLETEDP should be true if some completion was done, which doesn't include simply changing the case of the entered string. --- 1926,1932 ---- return 1; } ! string = Fminibuffer_completion_contents (); /* COMPLETEDP should be true if some completion was done, which doesn't include simply changing the case of the entered string. *************** *** 1988,1994 **** last_exact_completion = completion; if (!NILP (last)) { ! tem = minibuffer_completion_contents (); if (!NILP (Fequal (tem, last))) Fminibuffer_completion_help (); } --- 1993,1999 ---- last_exact_completion = completion; if (!NILP (last)) { ! tem = Fminibuffer_completion_contents (); if (!NILP (Fequal (tem, last))) Fminibuffer_completion_help (); } *************** *** 2191,2197 **** /* We keep calling Fbuffer_string rather than arrange for GC to hold onto a pointer to one of the strings thus made. */ ! completion = Ftry_completion (minibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate); if (NILP (completion)) --- 2196,2202 ---- /* We keep calling Fbuffer_string rather than arrange for GC to hold onto a pointer to one of the strings thus made. */ ! completion = Ftry_completion (Fminibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate); if (NILP (completion)) *************** *** 2223,2229 **** int buffer_nchars, completion_nchars; CHECK_STRING (completion); ! tem = minibuffer_completion_contents (); GCPRO2 (completion, tem); /* If reading a file name, expand any $ENVVAR refs in the buffer and in TEM. */ --- 2228,2234 ---- int buffer_nchars, completion_nchars; CHECK_STRING (completion); ! tem = Fminibuffer_completion_contents (); GCPRO2 (completion, tem); /* If reading a file name, expand any $ENVVAR refs in the buffer and in TEM. */ *************** *** 2287,2293 **** if (i == SCHARS (completion)) { GCPRO1 (completion); ! tem = Ftry_completion (concat2 (minibuffer_completion_contents (), build_string (" ")), Vminibuffer_completion_table, Vminibuffer_completion_predicate); --- 2292,2298 ---- if (i == SCHARS (completion)) { GCPRO1 (completion); ! tem = Ftry_completion (concat2 (Fminibuffer_completion_contents (), build_string (" ")), Vminibuffer_completion_table, Vminibuffer_completion_predicate); *************** *** 2299,2305 **** { GCPRO1 (completion); tem = ! Ftry_completion (concat2 (minibuffer_completion_contents (), build_string ("-")), Vminibuffer_completion_table, Vminibuffer_completion_predicate); --- 2304,2310 ---- { GCPRO1 (completion); tem = ! Ftry_completion (concat2 (Fminibuffer_completion_contents (), build_string ("-")), Vminibuffer_completion_table, Vminibuffer_completion_predicate); *************** *** 2371,2378 **** It is used to put faces, `completions-first-difference' and `completions-common-part' on the completion buffer. The `completions-common-part' face is put on the common substring ! specified by COMMON-SUBSTRING. If COMMON-SUBSTRING is nil, ! the faces are not put. Internally, COMMON-SUBSTRING is bound to `completion-common-substring' during running `completion-setup-hook'. */) (completions, common_substring) --- 2376,2383 ---- It is used to put faces, `completions-first-difference' and `completions-common-part' on the completion buffer. The `completions-common-part' face is put on the common substring ! specified by COMMON-SUBSTRING. If COMMON-SUBSTRING is nil ! and the current buffer is not the minibuffer, the faces are not put. Internally, COMMON-SUBSTRING is bound to `completion-common-substring' during running `completion-setup-hook'. */) (completions, common_substring) *************** *** 2563,2569 **** display_completion_list_1 (list) Lisp_Object list; { ! return Fdisplay_completion_list (list, minibuffer_completion_contents ()); } DEFUN ("minibuffer-completion-help", Fminibuffer_completion_help, Sminibuffer_completion_help, --- 2568,2574 ---- display_completion_list_1 (list) Lisp_Object list; { ! return Fdisplay_completion_list (list, Qnil); } DEFUN ("minibuffer-completion-help", Fminibuffer_completion_help, Sminibuffer_completion_help, *************** *** 2574,2580 **** Lisp_Object completions; message ("Making completion list..."); ! completions = Fall_completions (minibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate, Qt); --- 2579,2585 ---- Lisp_Object completions; message ("Making completion list..."); ! completions = Fall_completions (Fminibuffer_completion_contents (), Vminibuffer_completion_table, Vminibuffer_completion_predicate, Qt); *************** *** 2883,2888 **** --- 2888,2894 ---- defsubr (&Sminibuffer_prompt_end); defsubr (&Sminibuffer_contents); defsubr (&Sminibuffer_contents_no_properties); + defsubr (&Sminibuffer_completion_contents); defsubr (&Sdelete_minibuffer_contents); defsubr (&Stry_completion); Index: lisp/simple.el =================================================================== RCS file: /sources/emacs/emacs/lisp/simple.el,v retrieving revision 1.778 diff -c -r1.778 simple.el *** lisp/simple.el 10 Dec 2005 01:12:25 -0000 1.778 --- lisp/simple.el 14 Dec 2005 07:57:45 -0000 *************** *** 4901,4968 **** "Common prefix substring to use in `completion-setup-function' to put faces. The value is set by `display-completion-list' during running `completion-setup-hook'. ! To put faces, `completions-first-difference' and `completions-common-part' ! into \"*Completions*\* buffer, the common prefix substring in completions is ! needed as a hint. (Minibuffer is a special case. The content of minibuffer itself ! is the substring.)") ;; This function goes in completion-setup-hook, so that it is called ;; after the text of the completion list buffer is written. (defun completion-setup-function () (let* ((mainbuf (current-buffer)) ! (mbuf-contents (minibuffer-contents)) ! (common-string-length (length mbuf-contents))) ;; When reading a file name in the minibuffer, ;; set default-directory in the minibuffer ;; so it will get copied into the completion list buffer. ! (if minibuffer-completing-file-name (with-current-buffer mainbuf (setq default-directory (file-name-directory mbuf-contents)))) - ;; If partial-completion-mode is on, point might not be after the - ;; last character in the minibuffer. - ;; FIXME: This hack should be moved to complete.el where we call - ;; display-completion-list. - (when partial-completion-mode - (setq common-string-length - (if (eq (char-after (field-beginning)) ?-) - ;; If the text to be completed starts with a `-', there is no - ;; common prefix. - ;; FIXME: this probably still doesn't do the right thing - ;; when completing file names. It's not even clear what - ;; is TRT. - 0 - (- common-string-length (- (point-max) (point)))))) (with-current-buffer standard-output (completion-list-mode) (set (make-local-variable 'completion-reference-buffer) mainbuf) ! (setq completion-base-size ! (if minibuffer-completing-file-name ! ;; For file name completion, use the number of chars before ! ;; the start of the last file name component. ! (with-current-buffer mainbuf ! (save-excursion ! (goto-char (point-max)) ! (skip-chars-backward completion-root-regexp) ! (- (point) (minibuffer-prompt-end)))) ! ;; Otherwise, in minibuffer, the whole input is being completed. ! (if (minibufferp mainbuf) 0))) ! (if (and (symbolp minibuffer-completion-table) ! (get minibuffer-completion-table 'completion-base-size-function)) ! (setq completion-base-size ! ;; FIXME: without any extra arg, how is this function ! ;; expected to return anything else than a constant unless ! ;; it redoes part of the work of all-completions? ! ;; In most cases this value would better be computed and ! ;; returned at the same time as the list of all-completions ! ;; is computed. --Stef ! (funcall (get minibuffer-completion-table ! 'completion-base-size-function)))) ;; Put faces on first uncommon characters and common parts. ! (when (or completion-common-substring completion-base-size) ! (setq common-string-length ! (if completion-common-substring ! (length completion-common-substring) ! (- common-string-length completion-base-size))) (let ((element-start (point-min)) (maxp (point-max)) element-common-end) --- 4958,5011 ---- "Common prefix substring to use in `completion-setup-function' to put faces. The value is set by `display-completion-list' during running `completion-setup-hook'. ! To put faces `completions-first-difference' and `completions-common-part' ! in the *Completions* buffer, the common prefix substring in completions ! is needed as a hint. (The minibuffer is a special case. The content ! of the minibuffer before point is always the common substring.)") ;; This function goes in completion-setup-hook, so that it is called ;; after the text of the completion list buffer is written. (defun completion-setup-function () (let* ((mainbuf (current-buffer)) ! (mbuf-contents (and (minibufferp mainbuf) ! (minibuffer-completion-contents))) ! (common-substring (or completion-common-substring mbuf-contents)) ! common-string-length) ;; When reading a file name in the minibuffer, ;; set default-directory in the minibuffer ;; so it will get copied into the completion list buffer. ! (if (and minibuffer-completing-file-name mbuf-contents) (with-current-buffer mainbuf (setq default-directory (file-name-directory mbuf-contents)))) (with-current-buffer standard-output (completion-list-mode) (set (make-local-variable 'completion-reference-buffer) mainbuf) ! (if mbuf-contents ! (setq completion-base-size ! (cond ! ((and (symbolp minibuffer-completion-table) ! (get minibuffer-completion-table 'completion-base-size-function)) ! ;; To compute base size, this function can use the global value ! ;; of completion-common-substring or directly the contents of ! ;; the minibuffer. ! (with-current-buffer mainbuf ! (funcall (get minibuffer-completion-table ! 'completion-base-size-function)))) ! (minibuffer-completing-file-name ! ;; For file name completion, use the number of chars before ! ;; the start of the file name component at point. ! (with-current-buffer mainbuf ! (save-excursion ! (skip-chars-backward completion-root-regexp) ! (- (point) (minibuffer-prompt-end)))))))) ! (setq common-string-length ! (- (length common-substring) ! (if (and (integerp completion-base-size) ! (> completion-base-size 0)) ! completion-base-size ! 0))) ;; Put faces on first uncommon characters and common parts. ! (when (and (integerp common-string-length) (>= common-string-length 0)) (let ((element-start (point-min)) (maxp (point-max)) element-common-end) Index: lisp/complete.el =================================================================== RCS file: /sources/emacs/emacs/lisp/complete.el,v retrieving revision 1.47 diff -c -r1.47 complete.el *** lisp/complete.el 27 Nov 2005 20:53:55 -0000 1.47 --- lisp/complete.el 14 Dec 2005 07:55:34 -0000 *************** *** 613,620 **** (insert (substring prefix i (1+ i))) (setq end (1+ end))) (setq i (1+ i))) ! (or pt (equal (point) beg) ! (setq pt (point))) (looking-at PC-delim-regex)) (setq skip (concat skip (regexp-quote prefix) --- 613,619 ---- (insert (substring prefix i (1+ i))) (setq end (1+ end))) (setq i (1+ i))) ! (or pt (setq pt (point))) (looking-at PC-delim-regex)) (setq skip (concat skip (regexp-quote prefix) Index: lisp/info.el =================================================================== RCS file: /sources/emacs/emacs/lisp/info.el,v retrieving revision 1.467 diff -c -r1.467 info.el *** lisp/info.el 12 Dec 2005 05:15:53 -0000 1.467 --- lisp/info.el 14 Dec 2005 07:54:54 -0000 *************** *** 1517,1523 **** ;; Arrange to highlight the proper letters in the completion list buffer. (put 'Info-read-node-name-1 'completion-base-size-function ! (lambda () 1)) (defun Info-read-node-name (prompt &optional default) (let* ((completion-ignore-case t) --- 1523,1533 ---- ;; Arrange to highlight the proper letters in the completion list buffer. (put 'Info-read-node-name-1 'completion-base-size-function ! (lambda () ! (if (string-match "\\`([^)]*\\'" ! (or completion-common-substring ! (minibuffer-completion-contents))) ! 1))) (defun Info-read-node-name (prompt &optional default) (let* ((completion-ignore-case t) Index: lisp/emacs-lisp/crm.el =================================================================== RCS file: /sources/emacs/emacs/lisp/emacs-lisp/crm.el,v retrieving revision 1.9 diff -c -r1.9 crm.el *** lisp/emacs-lisp/crm.el 6 Aug 2005 17:08:59 -0000 1.9 --- lisp/emacs-lisp/crm.el 14 Dec 2005 07:52:34 -0000 *************** *** 234,240 **** t nil))) ! (defun crm-minibuffer-completion-help () "Display a list of possible completions of the current minibuffer element." (interactive) (message "Making completion list...") --- 234,240 ---- t nil))) ! (defun crm-minibuffer-completion-help (&optional common-substring) "Display a list of possible completions of the current minibuffer element." (interactive) (message "Making completion list...") *************** *** 247,253 **** (if (null completions) (crm-temp-echo-area-glyphs " [No completions]") (with-output-to-temp-buffer "*Completions*" ! (display-completion-list (sort completions 'string-lessp)))))) nil) (defun crm-do-completion () --- 247,255 ---- (if (null completions) (crm-temp-echo-area-glyphs " [No completions]") (with-output-to-temp-buffer "*Completions*" ! (display-completion-list ! (sort completions 'string-lessp) ! common-substring))))) nil) (defun crm-do-completion () *************** *** 303,309 **** (if completedp ; some completion happened (throw 'crm-exit 5) (if completion-auto-help ! (crm-minibuffer-completion-help) (crm-temp-echo-area-glyphs " [Next char not unique]"))) (throw 'crm-exit 6)) (if completedp --- 305,311 ---- (if completedp ; some completion happened (throw 'crm-exit 5) (if completion-auto-help ! (crm-minibuffer-completion-help crm-current-element) (crm-temp-echo-area-glyphs " [Next char not unique]"))) (throw 'crm-exit 6)) (if completedp *************** *** 313,319 **** (if (not (null last)) (progn (if (not (null (equal crm-current-element last))) ! (crm-minibuffer-completion-help)))) ;; returning -- was already an exact completion (throw 'crm-exit 3))))) --- 315,321 ---- (if (not (null last)) (progn (if (not (null (equal crm-current-element last))) ! (crm-minibuffer-completion-help crm-current-element)))) ;; returning -- was already an exact completion (throw 'crm-exit 3))))) -- Juri Linkov http://www.jurta.org/emacs/