Subject: Re: bug#50470: 27.1; 'company-mode' 'eshell'

From: Stefan Monnier <[email-masked]>
Date: Sat, 22 Jan 2022 22:23:42 -0500

> Some new details, from
> https://github.com/company-mode/company-mode/discussions/1276:
>
> When this happens (the user types a quote character and the tab character is
> inserted), there is a message in the echo area:
>
>   Completion function pcomplete-completions-at-point uses a deprecated
>   calling convention
>
> I'm going to add Stefan to Cc in case maybe he had a quick fix in mind,
> since I saw him reply to a similar-ish bug report about
> pcomplete integration.

I think I managed to reproduce the problem and get a good backtrace for
the above with:

    src/emacs -Q -l .../company/company-autoloads.el \
              -f eshell -f company-mode \
              --eval '(advice-add `pcomplete-completions-at-point :around (lambda (orig-fun &rest args) (let ((buffer-read-only t) (debug-on-signal t)) (apply orig-fun args))))' \
              --eval '(setq debug-on-error t debug-on-signal nil debug-ignored-errors nil)' \
              -l company.el \
              --eval "(progn (sit-for 1) (insert \"echo '\")      \
                             (company-idle-begin (current-buffer) \
                                                 (selected-window)\
                                                 (buffer-chars-modified-tick)\
                                                 (point)))"

And the 100% untested patch below is a suggestion for how to try and fix
those kinds of bugs.
Can someone try and maybe make it work?

        Stefan

diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index c6a51b1793..bc35c92493 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -311,18 +311,24 @@ eshell-completion-help
       (describe-prefix-bindings)
     (call-interactively 'pcomplete-help)))
 
+(defun eshell--pcomplete-insert-tab ()
+  (if (not pcomplete-allow-modifications)
+      (throw 'pcompleted nil)
+    (insert-and-inherit "\t")
+    (throw 'pcompleted t)))
+
 (defun eshell-complete-parse-arguments ()
   "Parse the command line arguments for `pcomplete-argument'."
   (when (and eshell-no-completion-during-jobs
 	     (eshell-interactive-process))
-    (insert-and-inherit "\t")
-    (throw 'pcompleted t))
+    (eshell--pcomplete-insert-tab))
   (let ((end (point-marker))
 	(begin (save-excursion (eshell-bol) (point)))
 	(posns (list t))
 	args delim)
-    (when (memq this-command '(pcomplete-expand
-			       pcomplete-expand-and-complete))
+    (when (and pcomplete-allow-modifications
+	       (memq this-command '(pcomplete-expand
+			            pcomplete-expand-and-complete)))
       (run-hook-with-args 'eshell-expand-input-functions begin end)
       (if (= begin end)
 	  (end-of-line))
@@ -335,14 +341,11 @@ eshell-complete-parse-arguments
 	       (setq begin (1+ (cadr delim))
 		     args (eshell-parse-arguments begin end)))
 	      ((eq (car delim) ?\()
-	       (eshell-complete-lisp-symbol)
-	       (throw 'pcompleted t))
+	       (throw 'pcompleted (elisp-completion-at-point)))
 	      (t
-	       (insert-and-inherit "\t")
-	       (throw 'pcompleted t))))
+	       (eshell--pcomplete-insert-tab))))
     (when (get-text-property (1- end) 'comment)
-      (insert-and-inherit "\t")
-      (throw 'pcompleted t))
+      (eshell--pcomplete-insert-tab))
     (let ((pos begin))
       (while (< pos end)
 	(if (get-text-property pos 'arg-begin)
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el
index 289312e0bb..f9c5b00719 100644
--- a/lisp/pcomplete.el
+++ b/lisp/pcomplete.el
@@ -189,6 +189,16 @@ pcomplete-expand-before-complete
 `pcomplete-parse-arguments-function'."
   :type 'boolean)
 
+(defvar pcomplete-allow-modifications nil
+  "If non-nil, allow effects in `pcomplete-parse-arguments-function'.
+For the `pcomplete' command, it was common for functions in
+`pcomplete-parse-arguments-function' to make modifications to the
+buffer, like expanding variables are such.
+For `completion-at-point-functions', this is not an option any more, so
+this variable is used to tell `pcomplete-parse-arguments-function'
+whether it can do the modifications like it used to, or whether
+it should refrain from doing so.")
+
 (defcustom pcomplete-parse-arguments-function
   #'pcomplete-parse-buffer-arguments
   "A function to call to parse the current line's arguments.
@@ -392,6 +402,9 @@ pcomplete-completions-at-point
   ;; imposing the pcomplete UI over the standard UI.
   (catch 'pcompleted
     (let* ((pcomplete-stub)
+           (buffer-read-only
+            ;; Make sure the function obeys `pcomplete-allow-modifications'.
+            (if pcomplete-allow-modifications buffer-read-only t))
            pcomplete-seen pcomplete-norm-func
            pcomplete-args pcomplete-last pcomplete-index
            (pcomplete-autolist pcomplete-autolist)
@@ -526,6 +539,7 @@ pcomplete
 	  pcomplete-last-completion-raw nil)
     (catch 'pcompleted
       (let* ((pcomplete-stub)
+	     (pcomplete-allow-modifications t)
 	     pcomplete-seen pcomplete-norm-func
 	     pcomplete-args pcomplete-last pcomplete-index
 	     (pcomplete-autolist pcomplete-autolist)