Skip to content

Commit

Permalink
decode: support "ble-bind -T" and "lib/vim-arpeggio.sh"
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Nov 14, 2019
1 parent 64a17c3 commit 272344e
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 20 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ outfiles += $(OUTDIR)/lib/core-syntax.sh
outfiles += $(OUTDIR)/lib/core-edit.ignoreeof-messages.txt
outfiles += $(OUTDIR)/lib/init-cmap.sh
outfiles += $(OUTDIR)/lib/vim-surround.sh
outfiles += $(OUTDIR)/lib/vim-arpeggio.sh
$(OUTDIR)/lib/%.sh: lib/%.sh | $(OUTDIR)/lib
cp -p $< $@
$(OUTDIR)/lib/%.txt: lib/%.txt | $(OUTDIR)/lib
Expand Down
12 changes: 8 additions & 4 deletions blerc
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,14 @@ function blerc/vim-load-hook {
# bleopt term_vi_cmap=

## vim-surround
# source "$_ble_base/lib/vim-surround.sh"
# bleopt vim_surround_45:=$'$( \r )'
# bleopt vim_surround_61:=$'$(( \r ))'

#source "$_ble_base/lib/vim-surround.sh"
#bleopt vim_surround_45:=$'$( \r )'
#bleopt vim_surround_61:=$'$(( \r ))'

## vim-arpeggio
#source "$_ble_base/lib/vim-arpeggio.sh"
#bleopt vim_arpeggio_timeoutlen=10
#ble/lib/vim-arpeggio.sh/bind -s jk 'hello'
}
blehook/eval-after-load keymap_vi blerc/vim-load-hook

Expand Down
56 changes: 56 additions & 0 deletions lib/vim-arpeggio.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/bash

source "$_ble_base/keymap/vi.sh"

bleopt/declare -v vim_arpeggio_timeoutlen 40

function ble/lib/vim-arpeggio.sh/bind/.usage {
ble/bin/echo "usage: ble/lib/vim-arpeggio.sh/bind [-m KEYMAP] -[fxcs@] KEYS COMMAND"
ble/bin/echo " KEYS has the form of {mods}{X}{Y}. {mods} are modifiers of the form"
ble/bin/echo " /([CSMAsH]-)*/ and {X} and {Y} are alphabets which specify simultaneous"
ble/bin/echo " keys."
}

function ble/lib/vim-arpeggio.sh/bind {
local -a opts=()
if [[ $1 == -m ]]; then
if [[ ! $2 ]]; then
ble/bin/echo "vim-arpeggio.sh: invalid option argument for \`-m'." >&2
ble/lib/vim-arpeggio.sh/bind/.usage >&2
return 1
fi
ble/array#push opts -m "$2"
shift 2
fi

local type=$1 keys=$2 cmd=$3
if [[ $type == --help ]]; then
ble/lib/vim-arpeggio.sh/bind/.usage
return 0
elif [[ $type != -[fxcs@] ]]; then
ble/bin/echo "vim-arpeggio.sh: invalid bind type." >&2
ble/lib/vim-arpeggio.sh/bind/.usage >&2
return 1
fi

local mods=
if local rex='^(([CSMAsH]-)+)..'; [[ $keys =~ $rex ]]; then
mods=${BASH_REMATCH[1]}
keys=${keys:${#mods}}
fi

local timeout=$((bleopt_vim_arpeggio_timeoutlen))
((timeout<0)) && timeout=

if ((${#keys}==2)); then
local k1=$mods${keys::1} k2=$mods${keys:1:1}
ble-bind "${opts[@]}" "$type" "$k1 $k2" "$cmd"
ble-bind "${opts[@]}" "$type" "$k2 $k1" "$cmd"
ble-bind "${opts[@]}" -T "$k1" "$timeout"
ble-bind "${opts[@]}" -T "$k2" "$timeout"
else
ble/bin/echo "vim-arpeggio.sh: sorry only 2-key bindings are supported now." >&2
ble/lib/vim-arpeggio.sh/bind/.usage >&2
return 1
fi
}
67 changes: 66 additions & 1 deletion memo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,10 @@ bash_tips
ToDo
-------------------------------------------------------------------------------

2019-11-14

* vim-arpeggio 及び ble-bind -T wiki に追記する

2019-10-21

* ずっと起動していると段々と遅くなっていくのは何故か。
Expand Down Expand Up @@ -2211,6 +2215,7 @@ bash_tips
- highlight: highlight word with the form of URL `#D1150` f48f2d7
- syntax: support syntax/globpat in param expansions `#D1157` `#D1158` 051222e `#D1160` 57b42ba
- syntax: fix attr of nested extglob in param expansions `#D1159` 2d019f0
- decode: support `ble-bind -T kspecs timeout` for timeout and `lib/vim-arpeggio.sh` `#D1174` 0000000

Changes
- edit: erase in page on `SIGWINCH` `#D1016` 7625ebe
Expand Down Expand Up @@ -2243,7 +2248,7 @@ bash_tips
- blehook: replace builtin `trap` `#D1152` d6c555e 7d4fd03
- blehook: suppress extra `DEBUG` trap calls `#D1155` 25c3e19
- syntax: allow `},fi,done,esac,then,...` after subshell `()` `#D1165` fdb49f3
- edit: support options `--help` for `read` and `exit` `#D1173` 0000000
- edit: support options `--help` for `read` and `exit` `#D1173` faccc6b

Fixes
- decode: workaround Poderosa that returns `DSR` instead of `CPR` in reply to `DSR(6)` `#D1018` 8e22c17
Expand Down Expand Up @@ -2292,6 +2297,8 @@ bash_tips
- complete: fix a problem of delay with path `//` in Cygwin `#D1168` 2cf8cc7
- prompt: fix the expansion of `\w` and `\W` in `PS1` for working directories with double slashes `#D1169` d1288dd
- exec: workaround termination of command execution on syntax error in array subscripts `#D1170` 4f442d0
- history: fix a bug that garbage `__ble_edt__` is added in front of history entries 61f4bd1
- decode: remove debug messages for `ble-bind -s` 64a17c3

Internal changes
- complete: isolate menu related codes `#D1029` 43bb074
Expand Down Expand Up @@ -3250,6 +3257,64 @@ bash_tips
Done (実装ログ)
-------------------------------------------------------------------------------

2019-11-14

* kj 及び jk の "同時押し" による操作の要望が来た [#D1174]
https://github.com/akinomyoga/ble.sh/issues/31

単独の k, j と区別する為には timeout に対応する必要がある。
これに対応する為にはどうすればよいか。

a ESC の受信に用いている方法は汎用的には使えない。
特に ESC の timeout と他の timeout を独立に設定できない。
そんなに重要な機能ではない様に思われるので、

b idle (bash-4.0 以降) を用いて実装するというのが良い気がする。
idle を用いて実装するとして timeout の情報をどの様に記録するのか
という問題が存在する。

調べてみると現在の実装ではそれまでに入力されたキーの
列から続きがあるかないかについて判定している。
つまりキーの列を登録する時に続きがあるかどうかも含めて
木の情報を構築している。ここに timeout の情報を記録するには、
先ず、各キー列に対する timeout を記録すると共に、
キー束縛を更新する度に最長の timeout を更新するという事が必要になる。

或いは別の方法として各キー列に対して timeout を設定するのではなくて、
各ノードに対して timeout を設定するという事にしても良いのかもしれない。
例えば jk 同時押しに対応するのだとしたら "j" と "k" に対して timeout
を設定しておく事にする。もし timeout が設定されていて続きがあるキーの場合には
"_100:command" を登録する事にする (100 が timeout である)。
もし待っているキーが存在しなくてかつ 100 待っても何も来なければこの時点で
command を実行する。待っているキーがあって 100 待つ内に続きのキーが到着したら、
続きのキーを処理してそれでも解決しなければ command を実行する様にすれば良い。
うーん。"解決しなかった時" は続きのキーが存在しない場合として処理する必要がある?

つまり、以下の様な方針で実装する必要がある。
* キー列の解決に失敗した時の再一致の際には timeout は無視してその場で確定する
* 通常の解決の際にだけ timeout を処理する事にする

現状の実装で再一致はどの様に実装していただろうか。
→.invoke-partial-match で特別に処理していた。
timeout を導入してもこの部分の処理を変更する必要はなさそう。OK

とりあえず実装した。結局 idle を使って実装するのではなくて、
その場で入力待ちをして実装する事にした。
timeout 待ちの状態で自動補完が走ったりしても混乱の元であるから、
却ってこの実装で良かったのではないかという気がする。

- bind, unbind, print で対応した。
- dispatch 及び invoke-partial-match でも対応した。
- "ble-bind -T kspecs timeout" に対応した。
注意としては kspecs を先頭部分に含む別の kspecs に対して
既に key bindings を設定している時にのみ使えるという事。

- github のページを確認して何が要求されているか改めて確認する。
- ユーティリティ関数を追加しても良いという気がする。
vim-arpeggio というのの説明を読んだ。
vim-arpeggio では3つ以上のキーも受け付ける様である。
何れにしてもユーティリティ関数を vim-arpeggio.sh という名前の拡張で提供する事にした。

2019-09-22

* edit: read, exit に --help を指定しても説明が表示されない [#D1173]
Expand Down
97 changes: 82 additions & 15 deletions src/decode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1072,14 +1072,16 @@ function ble-decode-char/dump {
##
## @value
## 以下の形式の何れかです。
## - "_"
## - "_:command"
## - "_" [TIMEOUT]
## - "_" [TIMEOUT] ":command"
## - "1:command"
##
## 始めの文字が "_" の場合はキーシーケンスに続きがある事を表します。
## つまり、このキーシーケンスを prefix とするより長いキーシーケンスが登録されている事を表します。
## command が指定されている場合には、より長いシーケンスでの一致に全て失敗した時点で
## command が実行されます。シーケンスを受け取った段階では実行されません。
## TIMEOUT (整数値) が指定されている場合は、このキーを受け取った後に続きのキーが TIMEOUT msec
## 以内に到着しなかった時に限りその場で command を実行します。
##
## 初めの文字が "1" の場合はキーシーケンスが確定的である事を表します。
## つまり、このキーシーケンスを prefix とするより長いシーケンスが登録されてなく、
Expand Down Expand Up @@ -1221,21 +1223,43 @@ function ble-decode-key/bind {
builtin eval "local ocmd=\${$dicthead$tseq[key]}"
if ((i+1==iN)); then
if [[ ${ocmd::1} == _ ]]; then
builtin eval "$dicthead$tseq[key]=_:\$cmd"
builtin eval "$dicthead$tseq[key]=${ocmd%%:*}:\$cmd"
else
builtin eval "$dicthead$tseq[key]=1:\$cmd"
fi
else
if [[ ! $ocmd ]]; then
builtin eval "$dicthead$tseq[key]=_"
elif [[ ${ocmd::1} == 1 ]]; then
builtin eval "$dicthead$tseq[key]=_:\${ocmd#?:}"
builtin eval "$dicthead$tseq[key]=_:\${ocmd#*:}"
fi
tseq=${tseq}_$key
fi
done
}

function ble-decode-key/set-timeout {
local dicthead=_ble_decode_${kmap}_kmap_
local -a seq; ble/string#split-words seq "$1"
local timeout=$2; [[ $timeout == - ]] && timeout=

local i iN=${#seq[@]}
local key=${seq[iN-1]}
local tseq=
for ((i=0;i<iN-1;i++)); do
tseq=${tseq}_${seq[i]}
done

builtin eval "local ent=\${$dicthead$tseq[key]}"
if [[ $ent == _* ]]; then
local cmd=; [[ $ent == *:* ]] && cmd=${ent#*:}
builtin eval "$dicthead$tseq[key]=_$timeout${cmd:+:}\$cmd"
else
ble/bin/echo "ble-bind -T: specified partial keyspec not found." >&2
return 1
fi
}

function ble-decode-key/unbind {
local dicthead=_ble_decode_${kmap}_kmap_
local -a seq; ble/string#split-words seq "$1"
Expand All @@ -1255,17 +1279,17 @@ function ble-decode-key/unbind {
# command を消す
isfirst=
if [[ ${ent::1} == _ ]]; then
# ent = _ または _:command の時は、単に command を消して終わる。
# ent = _[TIMEOUT] または _[TIMEOUT]:command の時は、単に command を消して終わる。
# (未だ bind が残っているので、登録は削除せず break)。
builtin eval "$dicthead$tseq[key]=_"
builtin eval "$dicthead$tseq[key]=\${ent%%:*}"
break
fi
else
# prefix の ent は _ か _:command のどちらかの筈。
if [[ $ent != _ ]]; then
if [[ $ent == *:* ]]; then
# _:command の場合には 1:command に書き換える。
# (1:command の bind が残っているので登録は削除せず break)。
builtin eval "$dicthead$tseq[key]=1:\${ent#?:}"
builtin eval "$dicthead$tseq[key]=1:\${ent#*:}"
break
fi
fi
Expand Down Expand Up @@ -1302,11 +1326,9 @@ function ble-decode-key/dump {
local ret; ble-decode-unkbd "$key"
local knames=$nseq${nseq:+ }$ret
builtin eval "local ent=\${$dicthead$tseq[key]}"
if [[ ${ent:2} ]]; then
local cmd=${ent:2} q=\' Q="'\''"
if [[ $ent == *:* ]]; then
local cmd=${ent#*:} q=\' Q="'\''"
case "$cmd" in
# ('ble/widget/.insert-string '*)
# ble/bin/echo "ble-bind -sf '${knames//$q/$Q}' '${cmd#ble/widget/.insert-string }'" ;;
('ble/widget/.SHELL_COMMAND '*)
ble/bin/echo "ble-bind$kmapopt -c '${knames//$q/$Q}' ${cmd#ble/widget/.SHELL_COMMAND }" ;;
('ble/widget/.EDIT_COMMAND '*)
Expand All @@ -1323,6 +1345,10 @@ function ble-decode-key/dump {

if [[ ${ent::1} == _ ]]; then
ble-decode-key/dump "$kmap" "${tseq}_$key" "$knames"
if [[ $ent == _[0-9]* ]]; then
local timeout=${ent%%:*}; timeout=${timeout:1}
ble/bin/echo "ble-bind$kmapopt -T '${knames//$q/$Q}' $timeout"
fi
fi
done
}
Expand Down Expand Up @@ -1431,7 +1457,8 @@ function ble/widget/__batch_char__.default {
##
function ble-decode-key {
local key
for key; do
while (($#)); do
key=$1; shift
#%if debug_keylogger
((_ble_keylogger_enabled)) && ble/array#push _ble_keylogger_keys "$key"
#%end
Expand Down Expand Up @@ -1459,6 +1486,22 @@ function ble-decode-key {
local dicthead=_ble_decode_${_ble_decode_keymap}_kmap_

builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[key]-}"

# TIMEOUT: timeout が設定されている場合はその時間だけ待って
# 続きを処理するかその場で確定するか判断する。
if [[ $ent == _[0-9]* ]]; then
local node_type=_
if (($#==0)) && ! ble-decode/has-input; then
local timeout=${ent%%:*}; timeout=${timeout:1}
ble-decode/wait-input "$timeout" || node_type=1
fi
if [[ $ent == *:* ]]; then
ent=$node_type:${ent#*:}
else
ent=$node_type
fi
fi

if [[ $ent == 1:* ]]; then
# /1:command/ (続きのシーケンスはなく ent で確定である事を示す)
local command=${ent:2}
Expand Down Expand Up @@ -1540,8 +1583,8 @@ function ble-decode-key/.invoke-partial-match {
_ble_decode_key__seq=${_ble_decode_key__seq%_*}

builtin eval "local ent=\${$dicthead$_ble_decode_key__seq[last]-}"
if [[ $ent == '_:'* ]]; then
local command=${ent:2}
if [[ $ent == _*:* ]]; then
local command=${ent#*:}
if [[ $command ]]; then
ble-decode/widget/.call-keyseq
else
Expand Down Expand Up @@ -1756,6 +1799,19 @@ function ble-decode/has-input {
# またユーザが続きを入力するのを待っている状態なので idle と思って良い。
# 従って ble-decode-key/is-intermediate についてはチェックしない。
}

## 関数 ble-decode/wait-input timeout
function ble-decode/wait-input {
local timeout=$1
while ((timeout>0)); do
ble-decode/has-input && return 0
local w=$((timeout<20?timeout:20))
ble/util/msleep "$w"
((timeout-=w))
done
return 1
}

function ble/util/idle/IS_IDLE {
! ble-decode/has-input
}
Expand Down Expand Up @@ -2000,6 +2056,7 @@ ble-bind --help
ble-bind -k cspecs [kspec]
ble-bind --csi PsFt kspec
ble-bind [-m keymap] -fxc@s kspecs command
ble-bind [-m keymap] -T kspecs timeout
ble-bind [-m keymap]... (-PD|--print|--dump)
ble-bind (-L|--list-widgets)
Expand Down Expand Up @@ -2201,6 +2258,16 @@ function ble-bind {
ble-decode-key/unbind "$kbd"
fi
shift 2 ;;
(T)
ble-decode-kbd "$1"; local kbd=$ret
if (($#<2)); then
ble/bin/echo "ble-bind: the option \`-T' requires two arguments." >&2
return 2
fi

[[ $kmap ]] || ble-decode/DEFAULT_KEYMAP -v kmap
ble-decode-key/set-timeout "$kbd" "$2"
shift 2 ;;
(L)
ble-bind/option:list-widgets ;;
(*)
Expand Down

0 comments on commit 272344e

Please sign in to comment.