help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Inner workings of `pcomplete'


From: Oleksandr Manzyuk
Subject: Inner workings of `pcomplete'
Date: Tue, 07 Feb 2012 23:31:03 +0000

Dear all,

I'm working on a small package aiming at providing basic completion for
GHCi commands in `inferior-haskell-mode':

https://github.com/manzyuk/ghci-completion

The package uses a combination of the standard completion UI (for GHCi
commands) with `pcomplete' (for arguments to particular commands).

I've been experimenting recently with identifier completion and I've
stumbled upon the following issue.  I'm not sure whether it is a bug in
the code or in my understanding of it.  Everything below refers to the
latest Emacs 24 (24.0.93.1).

To enable `pcomplete' in `inferior-haskell-mode', I add the function
`pcomplete-completions-at-point' to `comint-dynamic-complete-functions'.
Experimenting with identifier completion, I started to receive the
errors "Wrong type argument: stringp, nil", which I traced back to the
call

(pcomplete--common-quoted-suffix pcomplete-stub buftext)

in the body of `pcomplete-completions-at-point'.  Now, `pcomplete-stub'
is bound to nil at the beginning of the function using let* and it is
expected that the function `pcomplete-completions', which is called
later, will change the value of `pcomplete-stub' by side-effects.
Apparently, this doesn't happen and `pcomplete--common-quoted-suffix'
receives nil as its first argument, which triggers the error.

`pcomplete-stub' is declared using defvar, and the top comment of the
file contains -*- lexical-binding: t -*-, so `pcomplete-stub' should be
a special variable.  This is not the case:

1. emacs -Q
2. M-: (boundp 'pcomplete-stub) RET ==> nil
3. M-x shell
4. M-: (boundp 'pcomplete-stub) RET ==> t
5. M-: (special-variable-p 'pcomplete-stub) RET ==> nil
6. Open the file `pcomplete.el' (for example, by looking up the variable
`pcomplete-stub') and M-x eval-buffer.  Now (special-variable-p
'pcomplete-stub) evaluates to t.

What is going on here?

To confirm my guess that `pcomplete-stub' was not a special variable, I
tried the following workaround: I removed `pcomplete-stub' from the let*
bindings, so that no lexical binding was created for it, and hence its
global value was used in the body of let*.  The errors were gone and
completion started to work as I wanted it to.

Actually, to make identifier completion really work the way I wanted, I
had to make another change in `pcomplete-completions-at-point', namely
to replace

(when completions
  ...)

with 

(unless (functionp completions)
  ...)

The thing is, `completions' (the value returned by the function
`pcomplete-completions') can be a function.  In fact, it is a function
in the case of "cd" command in shell (try to type "cd " at the shell
prompt and M-: (pcomplete-completions)).  However, it is also passed as
a table argument to the function `complete-with-action', whose
documentation says that this argument should not be a function.  What
happens if it is a function?  I don't know, but somehow, with the old
code allowing `completions' to be a function, I get the behavior that
`pcomplete-completions-at-point' always succeeds (returns a suitably
formatted plist, even though its components don't always produce
completions!), leaving no opportunity to the next function in
`comint-dynamic-complete-functions' (identifier completion) to fire.

I should mention that by this change I've lost some of completion
functionality (e.g., "cd" in shell doesn't offer the list of
directories), so this is clearly not the right way to do it.  What is
the right way then?

I'm confused.  Any comments and suggestions would be greatly
appreciated.

Regards,
Sasha



reply via email to

[Prev in Thread] Current Thread [Next in Thread]