prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.28k stars 715 forks source link

Provide custom implementation of apply_completion #1912

Open contificate opened 3 weeks ago

contificate commented 3 weeks ago

Is there an idiomatic way of overriding the behaviour of apply_completion in Buffer?

I see that the default semantics, which is suitable for most applications, is:

self.delete_before_cursor(-completion.start_position)
self.insert_text(completion.text)

However, I have a kind of niche use-case which would be catered for better if there was an idiomatic way to reliably change this behaviour. For example, the most general interface I can imagine is effectively a function that rewrites the line and cursor position arbitrarily.

I apologise if there's a simple Python trick that I'm unaware of that would permit me to override this (I've tried various modifications to the example autocomplete-with-control-space.py to no avail) or if permitting this could have unintended interactions with other parts of the completer infrastructure that I haven't considered.

nitanmarcel commented 2 days ago

You can use inheriting to modify the behavior of a class method

https://docs.python.org/3/tutorial/classes.html#inheritance

contificate commented 2 days ago

You can use inheriting to modify the behavior of a class method

https://docs.python.org/3/tutorial/classes.html#inheritance

Yes, but I am not sure if there is an idiomatic way to actually thread this through. Suppose I overloaded apply_completion in a sub-class, how do I create a regular prompt that will use my custom buffer instance? Looks like most code samples query for the default buffer and never subclass Buffer itself. I tried some trickery to overload apply_completion in-place but it is neither effectual nor persistent.

nitanmarcel commented 2 days ago

You can use inheriting to modify the behavior of a class method https://docs.python.org/3/tutorial/classes.html#inheritance

Yes, but I am not sure if there is an idiomatic way to actually thread this through. Suppose I overloaded apply_completion in a sub-class, how do I create a regular prompt that will use my custom buffer instance? Looks like most code samples query for the default buffer and never subclass Buffer itself. I tried some trickery to overload apply_completion in-place but it is neither effectual nor persistent.

Uh? Just use your custom inherited class and use it instead of buffer. Unless you mean something else


class MyBuffer(Buffer):
    def __init__(self, use the same args as the original Buffer):
        super().__init__(self, the same args as above)
    def apply_completion(self, same args as the original function:
        #modify the function here

And instead of using Buffer() you use MyBuffer().

For example here's me modifying the initialization function of KeyBinds class to create my bindings by default when initialized

https://github.com/nitanmarcel/Sno-py/blob/9cc3d366aa28e300893ddef5925e2c12b7bb0d0f/src/sno_py/bindings.py#L7

And here instead of using KeyBinds() I'm using the modified class

https://github.com/nitanmarcel/Sno-py/blob/main/src/sno_py/snoedit.py#L67

nitanmarcel commented 2 days ago

.

You can use inheriting to modify the behavior of a class method https://docs.python.org/3/tutorial/classes.html#inheritance

Yes, but I am not sure if there is an idiomatic way to actually thread this through. Suppose I overloaded apply_completion in a sub-class, how do I create a regular prompt that will use my custom buffer instance? Looks like most code samples query for the default buffer and never subclass Buffer itself. I tried some trickery to overload apply_completion in-place but it is neither effectual nor persistent.

And if you want promt() call to use your buffer, override this to initialize your buffer

https://github.com/prompt-toolkit/python-prompt-toolkit/blob/435bd99cf2abb229c13d5b1106467c7f6af599ed/src/prompt_toolkit/shortcuts/prompt.py#L495

nitanmarcel commented 2 days ago

And you probably have to provide your own promt function that initializes your new class

https://github.com/prompt-toolkit/python-prompt-toolkit/blob/435bd99cf2abb229c13d5b1106467c7f6af599ed/src/prompt_toolkit/shortcuts/prompt.py#L1423

contificate commented 2 days ago

Alas, I have tried all levels of monkey patching to no avail.

This issue isn't really about whether or not there is a conceivable way to hack in what I want (there probably is, but I've been unable to get it to work) - it's a feature request to avoid having to hack it in. If you can supply a completer, why not also be allowed to specify how it completes?

The use-case I had in mind is being able to do auto-completion as a form of correction. If your cursor is within an erroneous portion of line input, a completer that is context-aware should effectively replace the erroneous segment (or keep the prefix) up to a synchronising token.