reddit / emacs
how to make orderless work in python shell
ntrysii · 2022-05-11 21:14
hi, Is there any way that could make completion in python inferior use orderless
i use completion-at-point-functions for completion.
in the python inferior only emacs22 and basic completion styles are working
setting completion-styles to '(orderless) will not show completions at all
those are the configurations for the python-shell buffer:
completion-at-point-function ( python-shell-completion-at-point comint-completion-at-point t)
completion-styles (basic emacs22 orderless)
completion-category-override nil
thanks in advance.
paretoOptimalDev · 2022-05-11 21:55
Corfu's or orderless' issue tracker has a relevant issue about lsp-mode and completion styles that might help you, but I don't have the link at hand.
oantolin · 2022-05-11 22:20
I'll explain the fix below, but first let me explain the issue. `orderless` internally works by translating your query to a list of regexps and then asks the completion table for all completions of the *empty string* that match each of the regexps. Now the completion mechanism in inferior python buffers when asked to complete the empty string goes, "The empty string? Are you crazy? The empty string is *not* a prefix of anything!". That's *very* wrong of course, but it's actually quite pragmatic: it's pretty reasonable to only complete non-empty strings and only as prefixes.
To help with this `orderless` has a little trick: if one of the resulting regexps after compiling your input to a list of regexps is of the form `^REGEXP` where `REGEXP` is equal to `(regexp-quote STRING)` for some `STRING`, then `orderless` takes the first such regexp and asks the completion table to complete `STRING`.
This means that if `^` where a valid character in Python identifiers, you could write stuff like `^foo` and press TAB to do completion in inferior python buffers. :P Of course, `^` is not valid in identifiers and even if it were, you wouldn't want to type `^` all the time!
OK, so finally the answer: the answer is to give up on the full power of orderless, and instead decide that in inferior Python buffers you will agree that the first component of the `orderless` input will be matched literally *and* anchored at the beginning. You can implement that as follows:
(defun first-anchored (pattern index _total)
(if (= index 0)
(cons 'orderless-regexp (concat "^" (regexp-quote pattern)))))
(orderless-define-completion-style orderless-for-python
;; add whatever you want here beyond first-anchored
(orderless-style-dispatchers '(first-anchored))
(orderless-matching-styles '(orderless-regexp)))
(defun inferior-python-completion-styles ()
(setq-local completion-styles '(orderless-for-python)))
(add-hook 'inferior-python-mode-hook #'inferior-python-completion-styles)
I hope the explanation and solution make sense, please ask if anything is unclear.
ntrysii · 2022-05-11 22:21
thanks i will search for that.
ntrysii · 2022-05-11 22:35
thanks for your time man i really appreciate it, I tried the code but it actually just
added a highlight that is used normally by corfu, but the completion functionality is the
same.
oantolin · 2022-05-11 22:37
I'll look into that. I did test that code and it works here, but I did not test with corfu...
oantolin · 2022-05-11 22:47
I just tried that configuration with corfu and it works just fine here! So I'm stumped as to why it doesn't work for you. The only thing I can think of is maybe you tried it on an existing inferior python buffer, not a new one that would pick up the new config.
ntrysii · 2022-05-11 22:51
actually no, i closed it and opened a new one, also i checked for completion-styles and it was set to orderless-for-python, would an emacs restart help ??
oantolin · 2022-05-11 22:57
No, restarting Emacs should not help. :( I have no idea why it's not working for you. I guess the next step is to try to reproduce from `emacs -q`: load just orderless and corfu, run that configuration and see if it works there. If so, then it's something else in your configuration and you'd have to start bisecting it.
ntrysii · 2022-05-11 23:03
thanks for your help man, i will check that out .
ExistingProgram3883 · 2022-05-12 05:23
Thank you very much, u/oantolin, for providing this solution.
Recently, I looked at `completing-read`, `try-completion`, but I don't get this sentence of your explanation:
> then asks the completion table for all completions of the
> empty string that match each of the regexps
Could you elaborate a bit, what's going on under the hood?
Thanks already in advance!
oantolin · 2022-05-12 10:02
Sure, what I mean is that `orderless` compiles your input into a list `regexps` of regexps to match and uses the following expression to get a list of all the strings in `completion-table` that match each of the elements of `regexps`:
(let ((completion-regexp-list regexps))
(all-completions "" completion-table))
It needs to use the empty string there because `(all-completions string table)` returns all strings in the completion table that match each element of `completion-regexp-list` and have `string` as a *prefix*. If you want to match `foo` anywhere, the only string you can be sure is a prefix of all the matches is the empty string. Many other completion styles also need to call `all-completions` with the empty string for the same reason, for example the built-in `substring` and `flex` styles do this.
> Thank you very much, u/oantolin, for providing this solution.
Can I ask you something? By using the word "solution" do you mean you tried this and it works for you? I wish I knew why it didn't work for u/ntrysii
ExistingProgram3883 · 2022-05-12 11:15
Thanks for clarification, I didn't know of `completion-regexp-list`, now it's perfectly clear.
> Can I ask you something? By using the word "solution" do you mean you > tried this and it works for you?
Sure, I tried it and it works as it should work -- at least as far I can tell. I get orderless matching -- all variables set as they should and `var long` gets completed as `long_var`.
patrick_thomson · 2022-05-12 15:05
I don’t have anything to add to this but I wanted to say that this is one of the best answers I’ve seen on this Reddit. Clarifies suppositions, explains features, provides code, all in clear and simple terms. Well done.
ExistingProgram3883 · 2022-05-15 10:14
I have to correct myself.
Unfortunately, the solution posted by you does not work.
I was in a hurry and didn't check it well enough. The variable `completion-styles` gets set to `(orderless-for-python)` for `#<buffer *Python*>` but it seems to utilize the `basic`-style.
Any idea why, u/oantolin?
oantolin · 2022-05-15 11:17
Well, the code I posted does make the *first* component match literally and anchored at the beginning, so it definitely feels like the `basic` style *for the first component* (and I explained in my initial comment why this was necessary, feel free to ask me about that if anything was unclear). But if you set `corfu-quit-at-boundary` to `nil` and press `SPC` you should be able to add more components for which you get normal `orderless` behavior.
ExistingProgram3883 · 2022-05-15 11:32
Thanks for clarification. I double checked everything, as you said, it feels very much like basic, when having `very_long_var_names` then it actually makes a difference. Thanks again for the help and orderless in general!