This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Added support for custom readline functions
Type: enhancement Stage: test needed
Components: Interpreter Core Versions: Python 3.2
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: John.Cherian, btimby, jimjjewett, martin.panter, paulhankin
Priority: normal Keywords: patch

Created on 2007-03-28 21:52 by btimby, last changed 2022-04-11 14:56 by admin.

Files
File name Uploaded Description Edit
python-2.3.4-readline_custom.patch btimby, 2007-03-28 21:52 Patch to add custom function hook to readline
python-2.3.4-readline_custom.patch btimby, 2007-03-28 23:00 A new patch which also includes the implementation of rl_on_new_line() which allows me to finalize the implementation of "cisco style help" using readline...
Messages (10)
msg52320 - (view) Author: Ben Timby (btimby) Date: 2007-03-28 21:52
This patch allows for binding a key or keyseq to a custom function named custom. A custom handler can be registered and will be called by readline when the registered sequence input.

Example:

rl.py
--
import readline

def handler():
    print "need some help?"

readline.set_custom_hook(handler)
readline.parse_and_bind("\"?\": custom")

text = raw_input("type ? for help# ")
--
msg52321 - (view) Author: Ben Timby (btimby) Date: 2007-03-28 23:00
File Added: python-2.3.4-readline_custom.patch
msg52322 - (view) Author: Ben Timby (btimby) Date: 2007-03-28 23:01
new Example:

rl.py
--
#!/usr/bin/python
import readline

def say_hello():
	print
	print "this is my help text..."
	readline.on_new_line()

readline.set_custom_hook(say_hello)
readline.parse_and_bind("\"?\": custom")

while True:
	data = raw_input("input# ")
	print "data: ", data
--
msg52323 - (view) Author: Paul Hankin (paulhankin) Date: 2007-04-01 21:47
Gnu readline supports custom functions in C - it would be better to adopt the gnu readline custom function interface to python, rather than using the 'custom' handler which smells of a hack.
msg52324 - (view) Author: Ben Timby (btimby) Date: 2007-04-02 01:53
If by adopt you mean adapt, that is what I have done. I simplified things to allow a single named function "custom" but it uses the gnu readline custom function interface (rl_add_defunc) . Have you even looked at the patch?
msg52325 - (view) Author: Paul Hankin (paulhankin) Date: 2007-04-02 17:28
Hi Ben, I'm sorry if you thought my short reply suggested I hadn't looked at the patch properly. I'll try to clarify what I meant.

Gnu readline provides an interface to custom functions: you declare a function that takes a 'count' and a 'key' and returns 0 or an error. You then call rl_add_defunc to declare it. You use the name you used in 'rl_add_defunc' in the readline init file to bind the command to a key.

The patch uses a different interface: the user provides a function that takes no arguments. He declares it by calling 'set_custom_hook', and calls it by using the name 'custom' in the init file to bind it to a key.

An interface consistent between python and readline would be:

def say_hello(key, count):
   ...
readline.add_defunc("say_hello", say_hello)
readline.parse_and_bind('"?" : say_hello')

(Perhaps the 'add_defun' is an artefact of lack of dynamic features of C and would be dropped from the python interface).

The patch's use of a 'custom' hook is more complicated than using the function name directly in the init file, and provides less functionality (a single command, and removes the arguments that the c command would have). Accepting this patch will cause minor compatibility trouble in future if anyone works out a way round the admittedly difficult technical problems of doing things the 'right' way.

Given the interface troubles, I'm not convinced enough of the usefulness of the patch.
msg52326 - (view) Author: Ben Timby (btimby) Date: 2007-04-03 11:59
Paul, thank you for clarifying. I agree with you completely. The reason I was unable to implement the API fully is the following problem (probably as you said due to the lack of dynamic features in C).

1. User defines python function.
2. User calls python readline.add_defun()
3. readline.add_defun() must whip up a C handler that will call the python function and in turn call rl_add_defun to register it. Problem being that multiple custom python functions registered with readline to a single C handler will have no way to determine which python function to call on invocation.
4. User calls readline.parse_and_bind()

I have no clue how to do step 3, so I avoided it. If anyone has suggestions, ideas or examples, I am happy to do the work, I simply have not had to do something like this before in C. I don't even know what this would be called in order to google for it.

The patch is certainly not as useful as the full API, however, I DID implement it to solve a problem, thus there is some use to it :-). I learned recently that I can maintain this feature as an extension (outside of) python, thus allowing me to continue to use it without depending on python maintainers to perceive usefulness. I will do this for the time being and if I am able to figure out item 3 I will resubmit the patch with a full implementation.
msg52327 - (view) Author: Jim Jewett (jimjjewett) Date: 2007-04-24 22:56
It looks as though you may have code from python 2.3.4 -- readline.c has been updated somewhat since then, particularly around threading.

I'm not sure I fully understand what you're asking in step 3.  It looks like on_hook(obj) will already call the python function well enough; you just need a way of keeping a reference to (and registering) a list of functions.

The module uses (single) static variables for the hooks it predefines, and you followed that model; you could just add a list of objects.  Instead of 


Then in set_custom_hook, instead of calling set_hook immediately, 

    /* Not tested, you might want a dict instead, you should error check, 
       you should pre-declare for C89, etc */

    if (NULL == custom_hooks) custom_hooks=PyList_New(0); /* no initial elements */

    PyList_Append(custom_hooks, args);  /* add your custom func, etc to the list */
    set_hook("  ", &(PyList_GET_ITEM(custom_hooks, PyList_GET_SIZE(custom_hooks))), *args);


(Or you could just inline the checks from set_hook.)

If you're feeling ambitious, you could fix set_hook itself to use a dictionary instead of specific pointers, or to get the name from the function.__name__, or to use a newer calling convention (As I understand it, the registration may really be METH_ONE, instead of METH_VARARGS.)
msg52328 - (view) Author: Ben Timby (btimby) Date: 2007-07-18 05:42
Jim, here is what I don't understand (item 3).

Currently, my patch (which is now an extension: http://ben.timby.com/pub/bt.tar.gz) works like so:

1. Module is initialized. rl_add_defun is called to register on_custom_hook as a handler for named function "custom".
2. User calls set_custom_hook. This simply sets custom_hook and custom_hook_tstate to proper values.
3. User calls readline.parse_and_bind to bind a key to the named function "custom".
4. When the bound key is pressed, readline invokes on_custom_hook, which in turn invokes the function provided by the user as a parameter to set_custom_hook (if it was valid).

This is simple, because there is only one custom function and one handler for it. In order to provide functionality for multiple handlers, you would as you described require a list. However, what would on_custom_hook look like? It receives only (int count, int key) how can it use these to look up the proper python function to invoke? Basically, how can it differentiate between the various registered handlers? Here is an example.

1. Module is initialized.
2. User calls set_custom_hook, and provides a function name and handler.
3. The function name and handler are stored in a list.
4. rl_add_defun is used to register ?? as a handler for the named function.
5. User calls readline.parse_and_bind to bind a key to their named function.
6. ?? does ?? when invoked to find the python handler for the named function.

Does that make any sense?
msg268973 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-06-21 06:24
See also Issue 1175004, proposing the same sort of custom function, but called “py_callback”.
History
Date User Action Args
2022-04-11 14:56:23adminsetgithub: 44781
2016-06-21 06:24:07martin.pantersetnosy: + martin.panter
messages: + msg268973
2014-06-22 17:53:32John.Cheriansetnosy: + John.Cherian
2010-08-09 04:10:49terry.reedysetversions: + Python 3.2, - Python 3.1, Python 2.7
2009-04-07 04:03:24ajaksu2setstage: test needed
type: enhancement
versions: + Python 3.1, Python 2.7, - Python 2.3
2007-03-28 21:52:03btimbycreate