terminalcommon-lispreadline

How to move the cursor on the editing line with cl-readline


I am trying to learn how to use cl-readline. One thing I want to do is bind the "(" key to a function, which inserts "()" and move the cursor between the two characters. I actually know how to do it with bash's bind command:

    bind '"(": "\C-q(\C-q)\C-b"'

But I have no idea how to do it with cl-readline. So far I have tried something like:

(defun insert-paren (arg key)
  (declare (ignore arg key))
  (rl:insert-text "()")
  (rl:insert-text (format nil "~C[1D" #\Esc)))

(rl:bind-keyseq "(" #'insert-paren)

According to https://tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html, "\033[1D" is the escape sequence to move the cursor backward.

But it does not work. It will insert the text like below, rather than move the cursor backward:

()^[[1D

Solution

  • cl-readline didn't have the forward and backward char functions, which are defined in readline.

    I pushed a commit that adds them (doc update and example usage there will come in the coming days).

    Here's an example, adapted from cl-readline-example. We bind a key that will insert text and move the cursor, once we get a readline prompt.

    
    (defun insert-and-move (arg key)
      (rl:insert-text "()")
      (rl:backward-char))  ;; edit: the 1 1 arguments are now optional.
    
    (defun run-example ()
      (rl:bind-keyseq "\\C-o" #'insert-and-move)
      (rl:bind-keyseq "(" #'insert-and-move)
      (rl:bind-keyseq "\\C-\(" #'insert-and-move)
    
      (handler-case
          (progn
            (rl:readline :prompt "my readline > ")
    
        … )
    
    (run-example)
    

    run the example:

    $ sbcl --script example.lisp
    

    now you can use ( or C-( or C-o to enter two ( ) and have the cursor in-between.