Bash – Modify $READLINE_LINE and $READLINE_POINT values inside bash script

autocompletebash

I already asked this question on stackoveflow, but received no answer and very few views. I thought I would post here as there should be more bash users and someone might have already stumbled upon this problem. According to SO Meta, it should be ok to do so as long as I link to the cross-website post. Tell me if I'm wrong though, and I'll just delete this question.


I tried to implement some features of ksh path autocompletion in bash by binding a custom script to a key. In order to do that, my script read the informations from bind variables $READLINE_LINE and $READLINE_POINT and attempts to update those values. While I can read the line buffer without issues, I can't seem to modify those variables and update the current line.

Quotting bind mand page, this should work though :

When shell-command is executed, the shell sets the READLINE_LINE variable to the contents of the readline line buffer and the READLINE_POINT variable to the current location of the insertion point. If the executed command changes the value of READLINE_LINE or READLINE_POINT, those new values will be reflected in the editing state

I bound my scipt with bind -x '"\t":autocomplete.sh', and did something like this :

#!/bin/bash
#autocomplete.sh
echo $READLINE_LINE $READLINE_POINT   #I can read the current line values
EXPANSION=($(magical_autocomplete $READLINE_LINE))
#we store the desired value for the line in ${EXPANSION[0]}
[[ ${#EXPANSION[@]} -gt 1 ]] && echo ${EXPANSION[@]:1} #we echo the match if there are more than 1

READLINE_LINE=${EXPANSION[0]}
READLINE_POINT=${#READLINE_LINE}
#echo READLINE_LINE READLINE_POINT echoes the correct values found by magical_autocomplete
#however the current line & the current point is not updated

As I am echo-ing some informations, I can't just redirect the ouptut of my script to $READLINE_LINE in the bind call. Why can I read from the variables but not write into them ?

Best Answer

Just by the same reason why this won’t work:

$ export a=1
$ bash -c 'echo $a; let a++'
1
$ echo $a
1

Environment variables are heritable, not shareable. Since autocomplete.sh is executed as a new child process, it can read all parent’s variables, but can‘t push new values back.

To modify READLINE_LINE and READLINE_POINT you have to execute your autocomplete in the same process – source and functions will help you.

# autocomplete.sh
# should be sourced from ~/.bashrc or something

autocomplete() {
    echo $READLINE_LINE $READLINE_POINT
    EXPANSION=($(magical_autocomplete $READLINE_LINE))
    #we store the desired value for the line in ${EXPANSION[0]}
    [[ ${#EXPANSION[@]} -gt 1 ]] && echo ${EXPANSION[@]:1}

    READLINE_LINE=${EXPANSION[0]}
    READLINE_POINT=${#READLINE_LINE}
}

Binding:

if [[ -s "$HOME/.bashrc.d/autocomplete.sh" ]]; then
    source "$HOME/.bashrc.d/autocomplete.sh" 
    bind -x '"\t" : autocomplete'
fi
Related Question