Subject: bug#73880: Master: emacs-lisp-mode: Tab completion for a function position fails in a `let' form.

From: Dmitry Gutov <[email-masked]>
Date: Sat, 26 Oct 2024 04:50:15 +0300

Hi Alan!

Sorry about the late response.

On 20/10/2024 13:54, Alan Mackenzie wrote:
> Hello, Dmitry and Emacs.
> 
> On Sat, Oct 19, 2024 at 13:09:00 +0000, Alan Mackenzie wrote:
>> Hello, Emacs.
> 
>> In a recent master version, for example this commit:
> 
>> commit 5340fdaade1f8fe7af08293619cca89ae0796fcf (HEAD -> master, origin/master, origin/HEAD)
>> Author: Alan Mackenzie <[email-masked]>
>> Date:   Wed Oct 16 13:17:26 2024 +0000
> 
>>      CC Mode: Fix dodgy lisp `let' form.
> 
>> , start emacs -Q, followed by entering the following incomplete form:
> 
>> (defun foo ()
>>    (let (
>>          )
>>      (match-b
> 
>> With point after match-b, type M-TAB.  This should complete to
>> match-beginning or show that function as a completion option.  Instead
>> it signals the error "No match".  This is a bug.
> 
>> It would seem the completion function elisp-completion-at-point thinks
>> it is completing a variable symbol rather than a function symbol.
> 
> This is indeed the case.  The following patch fixes this by checking
> that the symbol being completed begins within the binding list.  It also
> adds a test into elisp-mode-tests.el.

The test looks good, but for the fix itself maybe we could have 
something shorter. Could you try the below one-liner? It seems like the 
problem is the (forward-symbol -1) skipping over the empty parens.

This satisfies the test, at least.

BTW, I had to move the corresponding piece of code to a separate 
function to debug it. Too bad edebug doesn't know how to jump into the 
'guard' clauses.

diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 2f931daedc7..eab9b2d8ede 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -789,7 +789,7 @@ elisp-completion-at-point
                                        (goto-char (1- beg))
                                        (when (eq parent ?\()
                                          (up-list -1))
-                                      (forward-symbol -1)
+                                      (skip-syntax-backward " w_")
                                        (or
                                         (looking-at
                                          "\\_<\\(let\\*?\\|bind\\*\\)\\_>")