aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/shell_line_editor.sh418
1 files changed, 224 insertions, 194 deletions
diff --git a/common/shell_line_editor.sh b/common/shell_line_editor.sh
index 5e38ef4..8d6833a 100644
--- a/common/shell_line_editor.sh
+++ b/common/shell_line_editor.sh
@@ -4,214 +4,244 @@
LE_print_debug() {
LE_debug="$1"
LE_debug_msg="$2"
- [ -n "$LE_debug" ] && printf "\nDBG: (%s)\n" "$LE_debug_msg" > outfile.debug
+ [ -n "$LE_debug" ] && printf "\nDBG: (%s)\n" "$LE_debug_msg" >outfile.debug
}
LE() {
- # Shell Line Editor. Extremely slow and stupid code. However it
- # should work on ansi/vt100/linux derived terminals on POSIX
- # systems.
- # Understands some emacs key bindings: CTRL-(A,B,D,E,F,H,K,L)
- # plus the CTRL-W and CTRL-U normal killword and kill.
- # no Meta-X key, but handling of <Left>, <Right>, <Home>, <End>
- # <Suppr>.
- #
- # Args:
- # [1]: prompt (\x sequences recognized, defaults to "")
- # [2]: max input length (unlimited if < 0, (default))
- # [3]: fill character when erasing (defaults to space)
- # [4]: initial value.
- # [5]: whether to output debugfiles (outfile.debug and outfile.raw.debug)
- # Returns:
- # 0: OK
- # 1: od(d) error or CTRL-C hit
+ # Shell Line Editor. Extremely slow and stupid code. However it
+ # should work on ansi/vt100/linux derived terminals on POSIX
+ # systems.
+ # Understands some emacs key bindings: CTRL-(A,B,D,E,F,H,K,L)
+ # plus the CTRL-W and CTRL-U normal killword and kill.
+ # no Meta-X key, but handling of <Left>, <Right>, <Home>, <End>
+ # <Suppr>.
+ #
+ # Args:
+ # [1]: prompt (\x sequences recognized, defaults to "")
+ # [2]: max input length (unlimited if < 0, (default))
+ # [3]: fill character when erasing (defaults to space)
+ # [4]: initial value.
+ # [5]: whether to output debugfiles (outfile.debug and outfile.raw.debug)
+ # Returns:
+ # 0: OK
+ # 1: od(d) error or CTRL-C hit
- LE_prompt="$1"
- LE_max=${2--1}
- LE_fill=${3-" "}
- LE_debug="$5"
+ LE_prompt="$1"
+ LE_max=${2--1}
+ LE_fill=${3-" "}
+ LE_debug="$5"
- LE_backward() {
- LE_substract="$1"
- while [ -n "$LE_substract" ]; do
- printf '\b%s' "$2"
- LE_substract=${LE_substract%?}
- done
- }
+ LE_backward() {
+ LE_substract="$1"
+ while [ -n "$LE_substract" ]; do
+ printf '\b%s' "$2"
+ LE_substract=${LE_substract%?}
+ done
+ }
- LE_fill() {
- LE_substract="$1"
- while [ -n "$LE_substract" ]; do
- printf '%s' "$LE_fill"
- LE_substract=${LE_substract%?}
- done
- }
+ LE_fill() {
+ LE_substract="$1"
+ while [ -n "$LE_substract" ]; do
+ printf '%s' "$LE_fill"
+ LE_substract=${LE_substract%?}
+ done
+ }
- # Used but not right now
- # shellcheck disable=2016
- LE_restore='stty "$LE_tty"
+ # Used but not right now
+ # shellcheck disable=2016
+ LE_restore='stty "$LE_tty"
LC_COLLATE='${LC_COLLATE-"; unset LC_COLLATE"}
- # LE_tty is used in the restore above
- # shellcheck disable=2034
- LE_ret=1 LE_tty=$(stty -g) LC_COLLATE=C
+ # LE_tty is used in the restore above
+ # shellcheck disable=2034
+ LE_ret=1 LE_tty=$(stty -g) LC_COLLATE=C
- # text on the right of the cursor
- LE_left=$4
- # text on the left of the cursor
- LE_right=''
+ # text on the right of the cursor
+ LE_left=$4
+ # text on the left of the cursor
+ LE_right=''
- # Tell the terminal to show us every char inputted
- stty -icanon -echo -isig min 3 time 1 -istrip
- printf '%b%s' "$LE_prompt" "$LE_left"
+ # Tell the terminal to show us every char inputted
+ stty -icanon -echo -isig min 3 time 1 -istrip
+ printf '%b%s' "$LE_prompt" "$LE_left"
- # clear the output
- [ -n "$LE_debug" ] && printf "" > outfile.debug
- [ -n "$LE_debug" ] && printf "" > outfile.raw.debug
+ # clear the output
+ [ -n "$LE_debug" ] && printf "" >outfile.debug
+ [ -n "$LE_debug" ] && printf "" >outfile.raw.debug
- # The value needs to be split for it to work (and it's either way just numbers)
- # shellcheck disable=2046
- while set -- $(dd bs=3 count=1 2> /dev/null | od -vAn -to1); do
- while [ "$#" -gt 0 ]; do
- [ -n "$LE_debug" ] && printf "%b" "\0$1" >> outfile.debug
- [ -n "$LE_debug" ] && printf "%s " "$1" >> outfile.raw.debug
- LE_current_key=$1
- shift
-
- # 033 is ^[ (`printf "\\$1\n" | cat -v`)
- if [ "$LE_current_key" = 033 ]; then
- case "$1$2$3" in
- # [ C | O C -> ^F forward
- 133103*|117103*) shift 2; LE_current_key=006;;
- # [ D | O D -> ^B backward
- 133104*|117104*) shift 2; LE_current_key=002;;
- # [ H | O H -> ^A beginning of line
- 133110*|117110*) shift 2; LE_current_key=001;;
- # [ P | O P -> ^D del char
- 133120*|117120*) shift 2; LE_current_key=004;;
- # [ F | O F -> ^E end of line
- 133106*|117106*) shift 2; LE_current_key=005;;
- # [ 1 ~ -> ^A beginning of line
- 133061176) shift 3; LE_current_key=001;;
- # [ 4 ~ -> ^E end of line
- 133064176) shift 3; LE_current_key=005;;
- # [ 3 ~ -> ^D del char
- 133063176) shift 3; LE_current_key=004;;
- # [ | O
- 133*|117*)
+ # The value needs to be split for it to work (and it's either way just numbers)
+ # shellcheck disable=2046
+ while set -- $(dd bs=3 count=1 2>/dev/null | od -vAn -to1); do
+ while [ "$#" -gt 0 ]; do
+ [ -n "$LE_debug" ] && printf "%b" "\0$1" >>outfile.debug
+ [ -n "$LE_debug" ] && printf "%s " "$1" >>outfile.raw.debug
+ LE_current_key=$1
shift
- # Is $1 in ge 0 AND le 9 OR eq ';'?
- # These are control sequences for things like colors; Ignore them
- while [ "0$1" -ge 060 ] && [ "0$1" -le 071 ] ||
- [ "0$1" -eq 073 ]; do
- shift
- done;;
- esac
- fi
- case "$LE_current_key" in
- 001) # ^A beginning of line
- LE_backward "$LE_left"
- LE_right="$LE_left$LE_right"
- LE_left=;;
- 002) # ^B backward
- if [ "$LE_left" = "" ]; then
- # bell
- printf '\a'
- LE_print_debug "$LE_debug" "backward with empty left"
- else
- printf '\b'
- LE_tmp="${LE_left%?}"
- LE_right="${LE_left#"$LE_tmp"}$LE_right"
- LE_left="$LE_tmp"
- fi;;
- 003) # CTRL-C
- break 2;;
- 004) # ^D del char
- if [ "$LE_right" = "" ]; then
- # bell (tell the user that the line is empty)
- printf '\a'
- LE_print_debug "$LE_debug" "delete with empty right"
- else
- LE_right="${LE_right#?}"
- printf '%s\b' "$LE_right$LE_fill"
- LE_backward "$LE_right"
- fi;;
- 012|015) # NL or CR
- LE_ret=0
- break 2;;
- 005) # ^E end of line
- printf '%s' "$LE_right"
- LE_left="$LE_left$LE_right"
- LE_right=;;
- 006) # ^F forward
- if [ "$LE_right" = "" ]; then
- # bell (tell the user that the line is empty)
- printf '\a'
- LE_print_debug "$LE_debug" "forward with empty right"
- else
- LE_tmp="${LE_right#?}"
- LE_left="$LE_left${LE_right%"$LE_tmp"}"
- printf %s "${LE_right%"$LE_tmp"}"
- LE_right="$LE_tmp"
- fi;;
- 010|177) # backspace or del
- if [ "$LE_left" = "" ]; then
- # bell
- printf '\a'
- LE_print_debug "$LE_debug" "backspace with empty left"
- else
- printf '\b%s\b' "$LE_right$LE_fill"
- LE_backward "$LE_right"
- LE_left="${LE_left%?}"
- fi;;
- 013) # ^K kill to end of line
- LE_fill "$LE_right"
- LE_backward "$LE_right"
- LE_right=""
- ;;
- 014) # ^L redraw
- printf '\r%b%s' "$LE_prompt" "$LE_left$LE_right"
- LE_backward "$LE_right";;
- 025) # ^U kill line
- LE_backward "$LE_left"
- LE_fill "$LE_left$LE_right"
- LE_backward "$LE_left$LE_right"
- LE_left=""
- LE_right=""
- ;;
- 027) # ^W kill word
- if [ "$LE_left" = "" ]; then
- # bell
- printf '\a'
- else
- LE_tmp="${LE_left% *}"
- LE_backward "${LE_left#"$LE_tmp"}"
- LE_fill "${LE_left#"$LE_tmp"}"
- LE_backward "${LE_left#"$LE_tmp"}"
- LE_left="$LE_tmp"
- fi;;
- # Print the received key, as it did not match a special key
- [02][4-7]?|[13]??) # 040 -> 177, 240 -> 377
- # was assuming iso8859-x at the time
- if [ "$LE_max" -gt 0 ] && LE_tmp="$LE_left$LE_right" \
- && [ "${#LE_tmp}" -eq "$LE_max" ]; then
- # bell, when the user is trying to cross the line limit
- printf '\a'
- LE_print_debug "$LE_debug" "max output reached"
- else
- LE_left="$LE_left$(printf '%b' "\0$LE_current_key")"
- printf '%b%s' "\0$LE_current_key" "$LE_right"
- LE_backward "$LE_right"
- fi;;
- *)
- LE_print_debug "$LE_debug" "key not recognized: $(printf "%b" "\0$LE_current_key")"
- printf '\a';;
- esac
+ # 033 is ^[ (`printf "\\$1\n" | cat -v`)
+ if [ "$LE_current_key" = 033 ]; then
+ case "$1$2$3" in
+ # [ C | O C -> ^F forward
+ 133103* | 117103*)
+ shift 2
+ LE_current_key=006
+ ;;
+ # [ D | O D -> ^B backward
+ 133104* | 117104*)
+ shift 2
+ LE_current_key=002
+ ;;
+ # [ H | O H -> ^A beginning of line
+ 133110* | 117110*)
+ shift 2
+ LE_current_key=001
+ ;;
+ # [ P | O P -> ^D del char
+ 133120* | 117120*)
+ shift 2
+ LE_current_key=004
+ ;;
+ # [ F | O F -> ^E end of line
+ 133106* | 117106*)
+ shift 2
+ LE_current_key=005
+ ;;
+ # [ 1 ~ -> ^A beginning of line
+ 133061176)
+ shift 3
+ LE_current_key=001
+ ;;
+ # [ 4 ~ -> ^E end of line
+ 133064176)
+ shift 3
+ LE_current_key=005
+ ;;
+ # [ 3 ~ -> ^D del char
+ 133063176)
+ shift 3
+ LE_current_key=004
+ ;;
+ # [ | O
+ 133* | 117*)
+ shift
+ # Is $1 in ge 0 AND le 9 OR eq ';'?
+ # These are control sequences for things like colors; Ignore them
+ while [ "0$1" -ge 060 ] && [ "0$1" -le 071 ] ||
+ [ "0$1" -eq 073 ]; do
+ shift
+ done
+ ;;
+ esac
+ fi
+
+ case "$LE_current_key" in
+ 001) # ^A beginning of line
+ LE_backward "$LE_left"
+ LE_right="$LE_left$LE_right"
+ LE_left=
+ ;;
+ 002) # ^B backward
+ if [ "$LE_left" = "" ]; then
+ # bell
+ printf '\a'
+ LE_print_debug "$LE_debug" "backward with empty left"
+ else
+ printf '\b'
+ LE_tmp="${LE_left%?}"
+ LE_right="${LE_left#"$LE_tmp"}$LE_right"
+ LE_left="$LE_tmp"
+ fi ;;
+ 003) # CTRL-C
+ break 2 ;;
+ 004) # ^D del char
+ if [ "$LE_right" = "" ]; then
+ # bell (tell the user that the line is empty)
+ printf '\a'
+ LE_print_debug "$LE_debug" "delete with empty right"
+ else
+ LE_right="${LE_right#?}"
+ printf '%s\b' "$LE_right$LE_fill"
+ LE_backward "$LE_right"
+ fi ;;
+ 012 | 015) # NL or CR
+ LE_ret=0
+ break 2
+ ;;
+ 005) # ^E end of line
+ printf '%s' "$LE_right"
+ LE_left="$LE_left$LE_right"
+ LE_right=
+ ;;
+ 006) # ^F forward
+ if [ "$LE_right" = "" ]; then
+ # bell (tell the user that the line is empty)
+ printf '\a'
+ LE_print_debug "$LE_debug" "forward with empty right"
+ else
+ LE_tmp="${LE_right#?}"
+ LE_left="$LE_left${LE_right%"$LE_tmp"}"
+ printf %s "${LE_right%"$LE_tmp"}"
+ LE_right="$LE_tmp"
+ fi ;;
+ 010 | 177) # backspace or del
+ if [ "$LE_left" = "" ]; then
+ # bell
+ printf '\a'
+ LE_print_debug "$LE_debug" "backspace with empty left"
+ else
+ printf '\b%s\b' "$LE_right$LE_fill"
+ LE_backward "$LE_right"
+ LE_left="${LE_left%?}"
+ fi ;;
+ 013) # ^K kill to end of line
+ LE_fill "$LE_right"
+ LE_backward "$LE_right"
+ LE_right=""
+ ;;
+ 014) # ^L redraw
+ printf '\r%b%s' "$LE_prompt" "$LE_left$LE_right"
+ LE_backward "$LE_right"
+ ;;
+ 025) # ^U kill line
+ LE_backward "$LE_left"
+ LE_fill "$LE_left$LE_right"
+ LE_backward "$LE_left$LE_right"
+ LE_left=""
+ LE_right=""
+ ;;
+ 027) # ^W kill word
+ if [ "$LE_left" = "" ]; then
+ # bell
+ printf '\a'
+ else
+ LE_tmp="${LE_left% *}"
+ LE_backward "${LE_left#"$LE_tmp"}"
+ LE_fill "${LE_left#"$LE_tmp"}"
+ LE_backward "${LE_left#"$LE_tmp"}"
+ LE_left="$LE_tmp"
+ fi ;;
+ # Print the received key, as it did not match a special key
+ [02][4-7]? | [13]??) # 040 -> 177, 240 -> 377
+ # was assuming iso8859-x at the time
+ if [ "$LE_max" -gt 0 ] && LE_tmp="$LE_left$LE_right" &&
+ [ "${#LE_tmp}" -eq "$LE_max" ]; then
+ # bell, when the user is trying to cross the line limit
+ printf '\a'
+ LE_print_debug "$LE_debug" "max output reached"
+ else
+ LE_left="$LE_left$(printf '%b' "\0$LE_current_key")"
+ printf '%b%s' "\0$LE_current_key" "$LE_right"
+ LE_backward "$LE_right"
+ fi ;;
+ *)
+ LE_print_debug "$LE_debug" "key not recognized: $(printf "%b" "\0$LE_current_key")"
+ printf '\a'
+ ;;
+ esac
+ done
done
- done
- eval "$LE_restore"
- REPLY=$LE_left$LE_right
- echo
- return "$LE_ret"
+ eval "$LE_restore"
+ REPLY=$LE_left$LE_right
+ echo
+ return "$LE_ret"
}