zshzsh-zle

How zsh zle prevent variable CURSOR to be modified arbitrarily in runtime?


As the document says, the zle variable CURSOR can only be in range [0, $#BUFFER].

Test code (put it into .zshrc, the ^[OP is F1):

testCursor() {
  echo "\nOriginal C: $CURSOR"
  BUFFER="a"
  echo "Change Buffer: $CURSOR"
  CURSOR=$((CURSOR+10))
  echo "Force edit: $CURSOR"
  CURSOR=100
  echo "Force assign: $CURSOR"
}
zle -N testCursor
bindkey '^[OP' testCursor

enter image description here

The CURSOR satisfied it's range definition in runtime, how did the zsh-zle implements it?


Solution

  • The CURSOR value is handled in Zsh's source code, which is implemented in the C programming language: https://github.com/zsh-users/zsh/blob/3c93497eb701d8f220bc32d38e1f12bfb534c390/Src/Zle/zle_params.c#L266

    There is no way for you to declare a similarly constrained variable in Zsh shell code.

    However, you can write a math function for it instead:

    # Declare a global integer.
    typeset -gi TEST=0
    
    # -H makes these hidden, that is, not listed automatically.
    typeset -gHi _TEST_MIN=0 _TEST_MAX=10
    
    # Load `min` and `max` functions.
    autoload -Uz zmathfunc && zmathfunc
    
    set_test() {
      (( TEST = min(max($1,$_TEST_MIN),$_TEST_MAX) ))
    }
    
    get_test() {
      return $(( min(max($TEST,$_TEST_MIN),$_TEST_MAX) ))
    }
    
    # Declare `set_test` as a math function accepting exactly one numeric argument.
    functions -M set_test 1
    
    # Declare `get_test` as a math function accepting exactly zero arguments.
    functions -M get_test 0
    

    You can then use these in arithmetic statements, with this syntax:

    ❯ print $(( get_test() ))
    0
    
    ❯ (( set_test(100) ))
    
    ❯ print $(( get_test() ))
    10
    

    But also in other contexts, with this syntax:

    ❯ set_test -1
    
    ❯ get_test; print $?
    0