]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify in-buffer completion
authorEshel Yaron <me@eshelyaron.com>
Thu, 17 Oct 2024 15:19:24 +0000 (17:19 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 17 Oct 2024 15:26:19 +0000 (17:26 +0200)
lisp/comint.el
lisp/emacs-lisp/lisp.el
lisp/minibuffer.el
lisp/progmodes/eglot.el
lisp/simple.el

index d55bce63efc1d40bec07d39232c972b63da1ac7e..bed7e8244951980ec159c42b0824f941d877aeb0 100644 (file)
@@ -1934,12 +1934,6 @@ If the Comint is Lucid Common Lisp,
 
 Similarly for Soar, Scheme, etc."
   (interactive nil comint-mode)
-  ;; If we're currently completing, stop.  We're definitely done
-  ;; completing, and by sending the input, we might cause side effects
-  ;; that will confuse the code running in the completion
-  ;; post-command-hook.
-  (when completion-in-region-mode
-    (completion-in-region-mode -1))
   ;; Note that the input string does not include its terminal newline.
   (let ((proc (get-buffer-process (current-buffer))))
     (if (not proc) (user-error "Current buffer has no process")
index ba58f36b82902cf9668de8321d59424b86d4280f..a0c50bda84b34cc26036249ed98a9d9b3cea3c1c 100644 (file)
@@ -975,12 +975,6 @@ character."
                ;; mismatched.
                (user-error "Unmatched bracket or quote"))))
 \f
-(defun field-complete (table &optional predicate)
-  (declare (obsolete completion-in-region "24.4"))
-  (let ((minibuffer-completion-table table)
-        (minibuffer-completion-predicate predicate))
-    (call-interactively 'minibuffer-complete)))
-
 (defun lisp-complete-symbol (&optional _predicate)
   "Perform completion on Lisp symbol preceding point.
 Compare that symbol against the known Lisp symbols.
index 1d72cdbaf2e58bdef2c8ddb61716d950c4839b7d..8f0caf314fad0397322abea8408e73622772df84 100644 (file)
@@ -1788,8 +1788,7 @@ scroll the window of possible completions."
         (and (eq completion-auto-select t)
              (eq t (frame-visible-p (window-frame minibuffer-scroll-window)))
              ;; When the completion list window was displayed, select it.
-             (switch-to-completions))
-      (completion-in-region-mode -1))))
+             (switch-to-completions)))))
 
 (defun completion--metadata (string base md-at-point table pred)
   ;; Like completion-metadata, but for the specific case of getting the
@@ -3154,7 +3153,9 @@ completions list."
                        ;; completion is not finished.
                        (completion--done result
                                          (if (eq (car bounds) (length result))
-                                             'exact 'finished))))))))))))
+                                             'exact 'finished))))))))
+        (unless (minibufferp)
+          (set-transient-map completion-in-region-mode-map t #'minibuffer-hide-completions))))))
 
 (defun completions-display (completions &rest plist)
   "Display COMPLETIONS in the buffer specified by `standard-output'.
@@ -3285,31 +3286,12 @@ If nil, it defaults to 1."
       (throw 'exit (lambda () (minibuffer-quit-recursive-edit (1- levels))))
     (throw 'exit (lambda () (signal 'minibuffer-quit nil)))))
 
-(defvar completion-in-region-functions nil
-  "Wrapper hook around `completion--in-region'.
-\(See `with-wrapper-hook' for details about wrapper hooks.)")
-(make-obsolete-variable 'completion-in-region-functions
-                        'completion-in-region-function "24.4")
-
 (defvar completion-in-region-function #'completion--in-region
   "Function to perform the job of `completion-in-region'.
 The function is called with 4 arguments: START END COLLECTION PREDICATE.
 The arguments and expected return value are as specified for
 `completion-in-region'.")
 
-(defvar completion-in-region--data nil)
-
-(defvar completion-in-region-mode-predicate nil
-  "Predicate to tell `completion-in-region-mode' when to exit.
-It is called with no argument and should return nil when
-`completion-in-region-mode' should exit (and hence pop down
-the *Completions* buffer).")
-
-(defvar completion-in-region-mode--predicate nil
-  "Copy of the value of `completion-in-region-mode-predicate'.
-This holds the value `completion-in-region-mode-predicate' had when
-we entered `completion-in-region-mode'.")
-
 (defun completion-in-region (start end collection &optional predicate)
   "Complete the text between START and END using COLLECTION.
 Point needs to be somewhere between START and END.
@@ -3330,23 +3312,10 @@ if there was no valid completion, else t."
 
 (defun completion--in-region (start end collection &optional predicate)
   "Default function to use for `completion-in-region-function'.
-Its arguments and return value are as specified for `completion-in-region'.
-Also respects the obsolete wrapper hook `completion-in-region-functions'.
-\(See `with-wrapper-hook' for details about wrapper hooks.)"
-  (subr--with-wrapper-hook-no-warnings
-      ;; FIXME: Maybe we should use this hook to provide a "display
-      ;; completions" operation as well.
-      completion-in-region-functions (start end collection predicate)
-    (let ((minibuffer-completion-table collection)
-          (minibuffer-completion-predicate predicate))
-      ;; HACK: if the text we are completing is already in a field, we
-      ;; want the completion field to take priority (e.g. Bug#6830).
-      (when completion-in-region-mode-predicate
-        (setq completion-in-region--data
-             `(,(if (markerp start) start (copy-marker start))
-                ,(copy-marker end t) ,collection ,predicate))
-        (completion-in-region-mode 1))
-      (completion--in-region-1 start end))))
+Its arguments and return value are as specified for `completion-in-region'."
+  (let ((minibuffer-completion-table collection)
+        (minibuffer-completion-predicate predicate))
+    (completion--in-region-1 start end)))
 
 (defvar-keymap completion-in-region-mode-map
   :doc "Keymap activated during `completion-in-region'."
@@ -3357,67 +3326,10 @@ Also respects the obsolete wrapper hook `completion-in-region-functions'.
   "M-<right>" #'minibuffer-next-completion
   "M-RET"     #'minibuffer-choose-completion)
 
-;; It is difficult to know when to exit completion-in-region-mode (i.e. hide
-;; the *Completions*).  Here's how previous packages did it:
-;; - lisp-mode: never.
-;; - comint: only do it if you hit SPC at the right time.
-;; - pcomplete: pop it down on SPC or after some time-delay.
-;; - semantic: use a post-command-hook check similar to this one.
-(defun completion-in-region--postch ()
-  (or unread-command-events ;Don't pop down the completions in the middle of
-                            ;mouse-drag-region/mouse-set-point.
-      (and completion-in-region--data
-           (and (eq (marker-buffer (nth 0 completion-in-region--data))
-                    (current-buffer))
-                (>= (point) (nth 0 completion-in-region--data))
-                (<= (point)
-                    (save-excursion
-                      (goto-char (nth 1 completion-in-region--data))
-                      (line-end-position)))
-               (funcall completion-in-region-mode--predicate)))
-      (completion-in-region-mode -1)))
-
-;; (defalias 'completion-in-region--prech 'completion-in-region--postch)
-
-(defvar completion-in-region-mode nil)  ;Explicit defvar, i.s.o defcustom.
-
-(define-minor-mode completion-in-region-mode
-  "Transient minor mode used during `completion-in-region'."
-  :global t
-  :group 'minibuffer
-  ;; Prevent definition of a custom-variable since it makes no sense to
-  ;; customize this variable.
-  :variable completion-in-region-mode
-  ;; (remove-hook 'pre-command-hook #'completion-in-region--prech)
-  (remove-hook 'post-command-hook #'completion-in-region--postch)
-  (setq minor-mode-overriding-map-alist
-        (delq (assq 'completion-in-region-mode minor-mode-overriding-map-alist)
-              minor-mode-overriding-map-alist))
-  (if (null completion-in-region-mode)
-      (progn
-        (setq completion-in-region--data nil)
-        (unless (equal completions-buffer-name (buffer-name (window-buffer)))
-          (minibuffer-hide-completions)))
-    ;; (add-hook 'pre-command-hook #'completion-in-region--prech)
-    (cl-assert completion-in-region-mode-predicate)
-    (setq completion-in-region-mode--predicate
-         completion-in-region-mode-predicate)
-    (setq-local minibuffer-completion-auto-choose nil)
-    (add-hook 'post-command-hook #'completion-in-region--postch)
-    (push `(completion-in-region-mode . ,completion-in-region-mode-map)
-          minor-mode-overriding-map-alist)))
-
-;; Define-minor-mode added our keymap to minor-mode-map-alist, but we want it
-;; on minor-mode-overriding-map-alist instead.
-(setq minor-mode-map-alist
-      (delq (assq 'completion-in-region-mode minor-mode-map-alist)
-            minor-mode-map-alist))
-
 (defvar completion-at-point-functions nil
   "Special hook to find the completion table for the entity at point.
 Each function on this hook is called in turn without any argument and
 should return either nil, meaning it is not applicable at point,
-or a function of no arguments to perform completion (discouraged),
 or a list of the form (START END COLLECTION . PROPS), where:
  START and END delimit the entity to complete and should include point,
  COLLECTION is the completion table to use to complete the entity, and
@@ -3437,109 +3349,41 @@ which kind of completion table to use, and not pre-filter it based
 on the current text between START and END (e.g., they should not
 obey `completion-styles').")
 
-(defvar completion--capf-misbehave-funs nil
-  "List of functions found on `completion-at-point-functions' that misbehave.
-These are functions that neither return completion data nor a completion
-function but instead perform completion right away.")
-(defvar completion--capf-safe-funs nil
-  "List of well-behaved functions found on `completion-at-point-functions'.
-These are functions which return proper completion data rather than
-a completion function or god knows what else.")
-
-(defun completion--capf-wrapper (fun which)
-  ;; FIXME: The safe/misbehave handling assumes that a given function will
-  ;; always return the same kind of data, but this breaks down with functions
-  ;; like comint-completion-at-point or mh-letter-completion-at-point, which
-  ;; could be sometimes safe and sometimes misbehaving (and sometimes neither).
-  (if (pcase which
-        ('all t)
-        ('safe (member fun completion--capf-safe-funs))
-        ('optimist (not (member fun completion--capf-misbehave-funs))))
-      (let ((res (funcall fun)))
-        (cond
-         ((and (consp res) (not (functionp res)))
-          (unless (member fun completion--capf-safe-funs)
-            (push fun completion--capf-safe-funs))
-          (and (eq 'no (plist-get (nthcdr 3 res) :exclusive))
-               ;; FIXME: Here we'd need to decide whether there are
-               ;; valid completions against the current text.  But this depends
-               ;; on the actual completion UI (e.g. with the default completion
-               ;; it depends on completion-style) ;-(
-               ;; We approximate this result by checking whether prefix
-               ;; completion might work, which means that non-prefix completion
-               ;; will not work (or not right) for completion functions that
-               ;; are non-exclusive.
-               (null (try-completion (buffer-substring-no-properties
-                                      (car res) (point))
-                                     (nth 2 res)
-                                     (plist-get (nthcdr 3 res) :predicate)))
-               (setq res nil)))
-         ((not (or (listp res) (functionp res)))
-          (unless (member fun completion--capf-misbehave-funs)
-            (message
-             "Completion function %S uses a deprecated calling convention" fun)
-            (push fun completion--capf-misbehave-funs))))
-        (if res (cons fun res)))))
+(defun completion--capf-wrapper (fun &optional _)
+  (let ((res (funcall fun)))
+    (cond
+     ((and (consp res) (not (functionp res)))
+      (and (eq 'no (plist-get (nthcdr 3 res) :exclusive))
+           (null (completion-try-completion (buffer-substring-no-properties
+                                             (car res) (point))
+                                            (nth 2 res)
+                                            (plist-get (nthcdr 3 res) :predicate)
+                                            (- (point) (car res))))
+           (setq res nil))))
+    res))
 
 (defun completion-at-point ()
   "Perform completion on the text around point.
 The completion method is determined by `completion-at-point-functions'."
   (interactive)
-  (let ((res (run-hook-wrapped 'completion-at-point-functions
-                               #'completion--capf-wrapper 'all)))
-    (pcase res
-      (`(,_ . ,(and (pred functionp) f)) (funcall f))
-      (`(,hookfun . (,start ,end ,collection . ,plist))
-       (unless (markerp start) (setq start (copy-marker start)))
-       (let* ((completion-extra-properties plist)
-              (completion-in-region-mode-predicate
-               (lambda ()
-                 ;; We're still in the same completion field.
-                 (let ((newstart (car-safe (funcall hookfun))))
-                   (and newstart (= newstart start))))))
-         (completion-in-region start end collection
-                               (plist-get plist :predicate))))
-      ;; Maybe completion already happened and the function returned t.
-      (_
-       (when (cdr res)
-         (message "Warning: %S failed to return valid completion data!"
-                  (car res)))
-       (cdr res)))))
+  (pcase (run-hook-wrapped 'completion-at-point-functions #'completion--capf-wrapper)
+    (`(,start ,end ,collection . ,plist)
+     (unless (markerp start) (setq start (copy-marker start)))
+     (let* ((completion-extra-properties plist))
+       (completion-in-region start end collection
+                             (plist-get plist :predicate))))))
 
 (defun completion-help-at-point ()
   "Display the completions on the text around point.
 The completion method is determined by `completion-at-point-functions'."
   (interactive)
-  (let ((res (run-hook-wrapped 'completion-at-point-functions
-                               ;; Ignore misbehaving functions.
-                               #'completion--capf-wrapper 'optimist)))
-    (pcase res
-      (`(,_ . ,(and (pred functionp) f))
-       (message "Don't know how to show completions for %S" f))
-      (`(,hookfun . (,start ,end ,collection . ,plist))
-       (unless (markerp start) (setq start (copy-marker start)))
-       (let* ((minibuffer-completion-table collection)
-              (minibuffer-completion-predicate (plist-get plist :predicate))
-              (completion-extra-properties plist)
-              (completion-in-region-mode-predicate
-               (lambda ()
-                 ;; We're still in the same completion field.
-                 (let ((newstart (car-safe (funcall hookfun))))
-                   (and newstart (= newstart start))))))
-         ;; FIXME: We should somehow (ab)use completion-in-region-function or
-         ;; introduce a corresponding hook (plus another for word-completion,
-         ;; and another for force-completion, maybe?).
-         (setq completion-in-region--data
-               `(,start ,(copy-marker end t) ,collection
-                        ,(plist-get plist :predicate)))
-         (completion-in-region-mode 1)
-         (minibuffer-completion-help start end)))
-      (`(,hookfun . ,_)
-       ;; The hook function already performed completion :-(
-       ;; Not much we can do at this point.
-       (message "%s already performed completion!" hookfun)
-       nil)
-      (_ (message "Nothing to complete at point")))))
+  (pcase (run-hook-wrapped 'completion-at-point-functions #'completion--capf-wrapper)
+    (`(,start ,end ,collection . ,plist)
+     (unless (markerp start) (setq start (copy-marker start)))
+     (let* ((minibuffer-completion-table collection)
+            (minibuffer-completion-predicate (plist-get plist :predicate))
+            (completion-extra-properties plist))
+       (minibuffer-completion-help start end)))))
 
 ;;; Key bindings.
 
@@ -5905,12 +5749,10 @@ instead of the default completion table."
                       history)
             (user-error "No history available"))))
     ;; FIXME: Can we make it work for CRM?
-    (let ((completion-in-region-mode-predicate
-           (lambda () (get-buffer-window completions-buffer-name 0))))
-      (completion-in-region
-       (minibuffer--completion-prompt-end) (point-max)
-       (completion-table-with-metadata
-        completions '((sort-function   . identity)))))))
+    (completion-in-region
+     (minibuffer--completion-prompt-end) (point-max)
+     (completion-table-with-metadata
+      completions '((sort-function   . identity))))))
 
 (defun minibuffer-complete-defaults ()
   "Complete minibuffer defaults as far as possible.
@@ -5921,9 +5763,7 @@ instead of the completion table."
              (functionp minibuffer-default-add-function))
     (setq minibuffer-default-add-done t
           minibuffer-default (funcall minibuffer-default-add-function)))
-  (let ((completions (ensure-list minibuffer-default))
-        (completion-in-region-mode-predicate
-         (lambda () (get-buffer-window completions-buffer-name 0))))
+  (let ((completions (ensure-list minibuffer-default)))
     (completion-in-region
      (minibuffer--completion-prompt-end) (point-max)
      (completion-table-with-metadata
index 239dfd034a7d23fecb0835aeeb6ef5f8ed985272..f03f5c2940da3bb1f9c0aecbeca45959aecd2682 100644 (file)
@@ -2022,7 +2022,6 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
       (add-hook 'xref-backend-functions #'eglot-xref-backend nil t))
     (add-hook 'refactor-backend-functions #'eglot-refactor-backend nil t)
     (add-hook 'completion-at-point-functions #'eglot-completion-at-point nil t)
-    (add-hook 'completion-in-region-mode-hook #'eglot--capf-session-flush nil t)
     (add-hook 'company-after-completion-hook #'eglot--capf-session-flush nil t)
     (add-hook 'change-major-mode-hook #'eglot--managed-mode-off nil t)
     (add-hook 'post-self-insert-hook #'eglot--post-self-insert-hook nil t)
@@ -2054,7 +2053,6 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
     (remove-hook 'after-save-hook #'eglot--signal-textDocument/didSave t)
     (remove-hook 'xref-backend-functions #'eglot-xref-backend t)
     (remove-hook 'completion-at-point-functions #'eglot-completion-at-point t)
-    (remove-hook 'completion-in-region-mode-hook #'eglot--capf-session-flush t)
     (remove-hook 'company-after-completion-hook #'eglot--capf-session-flush t)
     (remove-hook 'change-major-mode-hook #'eglot--managed-mode-off t)
     (remove-hook 'post-self-insert-hook #'eglot--post-self-insert-hook t)
index 8d303aa5d28706100dd507f5f3359080eb7bf6e8..f05d865f6b78d3173256b8dae63c966e4bf184a6 100644 (file)
@@ -9462,8 +9462,6 @@ At top-level, as an editor command, this simply beeps."
     (deactivate-mark))
   (if (fboundp 'kmacro-keyboard-quit)
       (kmacro-keyboard-quit))
-  (when completion-in-region-mode
-    (completion-in-region-mode -1))
   ;; Force the next redisplay cycle to remove the "Def" indicator from
   ;; all the mode lines.
   (if defining-kbd-macro