Skip to content

Added support for custom readline functions #44781

Open

Description

@btimby
mannequin
BPO 1690201
Nosy @vadmium
Files
  • python-2.3.4-readline_custom.patch: Patch to add custom function hook to readline
  • python-2.3.4-readline_custom.patch: 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...
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2007-03-28.21:52:03.000>
    labels = ['interpreter-core', 'type-feature']
    title = 'Added support for custom readline functions'
    updated_at = <Date 2016-06-21.06:24:07.526>
    user = 'https://bugs.python.org/btimby'

    bugs.python.org fields:

    activity = <Date 2016-06-21.06:24:07.526>
    actor = 'martin.panter'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2007-03-28.21:52:03.000>
    creator = 'btimby'
    dependencies = []
    files = ['7905', '7906']
    hgrepos = []
    issue_num = 1690201
    keywords = ['patch']
    message_count = 10.0
    messages = ['52320', '52321', '52322', '52323', '52324', '52325', '52326', '52327', '52328', '268973']
    nosy_count = 5.0
    nosy_names = ['jimjjewett', 'paulhankin', 'btimby', 'martin.panter', 'John.Cherian']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'test needed'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue1690201'
    versions = ['Python 3.2']

    Activity

    1. btimby commented on Mar 28, 2007

      btimbymannequin
      MannequinAuthor

      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# ")
      --
    2. btimby commented on Mar 28, 2007

      btimbymannequin
      MannequinAuthor

      File Added: python-2.3.4-readline_custom.patch

    3. btimby commented on Mar 28, 2007

      btimbymannequin
      MannequinAuthor

      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
      --
    4. paulhankin commented on Apr 1, 2007

      paulhankinmannequin
      Mannequin

      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.

    5. btimby commented on Apr 2, 2007

      btimbymannequin
      MannequinAuthor

      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?

    6. paulhankin commented on Apr 2, 2007

      paulhankinmannequin
      Mannequin

      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.

    7. btimby commented on Apr 3, 2007

      btimbymannequin
      MannequinAuthor

      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.

    8. jimjjewett commented on Apr 24, 2007

      jimjjewettmannequin
      Mannequin

      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.)

    9. btimby commented on Jul 18, 2007

      btimbymannequin
      MannequinAuthor

      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?

    10. vadmium commented on Jun 21, 2016

      @vadmium
      Member

      See also bpo-1175004, proposing the same sort of custom function, but called “py_callback”.

    11. transferred this issue fromon Apr 10, 2022
    12. soreavis commented on Jul 19, 2026

      @soreavis
      Contributor

      This looks like a duplicate of #41788 (bpo-1175004). The ask here — bind a custom Python function to a readline key via rl_add_defun — is the same callback mechanism #41788 requests, and #41788 also covers the rl_on_new_line export this patch adds; Martin Panter linked the two in 2016 as "the same sort of custom function". None of it has landed (checked at 3.16: the readline module exposes none of these), and the patch here was written against 2.3.4 and self-retired — the code moved to an external extension. Closing this as a duplicate of #41788 would lose nothing; #41788 stays the canonical readline-exports issue.

      Quick check at current main (6df4993)
      import readline, sys
      print(sys.version)
      wanted = ["set_custom_hook", "set_py_callback_hook", "on_new_line",
                "delete_text", "message", "forced_update_display", "position_cursor"]
      print("present in readline:", [n for n in wanted if hasattr(readline, n)] or "none of them")
      3.16.0a0 (remotes/upstream/HEAD:6df4993bb64, Jul 19 2026, 20:24:53) [Clang 21.0.0 (clang-2100.1.1.101)]
      present in readline: none of them
      
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      interpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions