Skip to content

Commit

Permalink
decode: cache "inputrc" translations
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Sep 22, 2021
1 parent 9a7c8b1 commit 994e2a5
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 8 deletions.
1 change: 1 addition & 0 deletions memo/ChangeLog.md
Expand Up @@ -183,6 +183,7 @@
- history: use `mapfile -d ''` to load history in Bash 5.2 `#D1603` 72c274e
- prompt: use `${PS1@P}` when the prompt contains only safe prompt sequences `#D1617` 8b5da08
- prompt: fix not properly set `$?` in `${PS1@P}` evaluation (reported by nihilismus) `#D1644` 521aff9
- decode: cache `inputrc` translations `#D1652` 0000000

## Compatibility

Expand Down
113 changes: 113 additions & 0 deletions note.txt
Expand Up @@ -5372,6 +5372,119 @@ bash_tips
Done (実装ログ)
-------------------------------------------------------------------------------

2021-09-22

* decode: 巨大 inputrc の翻訳内容をキャッシュする [#D1652]
https://github.com/Bash-it/bash-it/pull/1884#issuecomment-923489130

/etc/inputrc{,.keys} が大量に設定を行っている為に初期化が物凄く遅い問題に
ついて。これは bash の既定の binding に対する cmap cache だけではなくて、
前回の ble.sh 実行時の cmap cache も保持する事で解決する様な気もする。と
いうか寧ろ前回の ble.sh 実行時の状態を使って cmap cache を保持するべきの
気もする。

[現状]

現在どの様にキャッシュしているか確認する。

例えば decode.readline.50108.vi-insert.txt 等に対して保存されている。これ
に対してユーザーが保存した物も付け加えるのはどうだろうか。と思ったが
emacs, vi-insert, vi-command で分けて保存しているのはどういう事だろうか。
うーん。emacs/vi-insert/vi-command の三組で ble.sh の keybinding の状態が
定まる。という事を思うと、ユーザーの inputrc の状態を保存するとしてもやは
り三組を記録する必要がある。そして、それらの保存されたファイルと現在の状
態に相違がない時に限り保存された keybinding の状態を復元するという振る舞
いにする。

--noinputrc で分岐している部分を確認する。noinputrc が指定されている時に
は以下の変数に値を設定している。これらの変数に値が設定されていない時に限
り現在の状態が読み取られる。

_ble_builtin_bind_inputrc_done=noinputrc

これは ble/builtin/bind/initialize-inputrc で参照される。ユーザーの
inputrc を読み取る関数。

_ble_builtin_bind_user_settings_loaded=noinputrc

これは現在の bind -vetc の出力を元に keybinding を設定する関数
ble/builtin/bind/read-user-settings 及び
ble/builtin/bind/.reconstruct-user-settings で処理される。

うーん。この .reconstruct-user-settings の中で呼び出している各ステップで
どれだけ時間がかかっているのかを計測するのが先ずはする事の気がする。もし
かすると bottleneck を見誤っているかもしれない。

実際に時間を計測してみると、比較対象と現在の状態の両方を gawk に入力する
為に集めるので 0.04s かかっている。gawk は 0.016s で終わっている。その後
の ble-bind で 0.77s 消費している。

[修正]

* ok: 入力情報を集める部分については恐らく設定の量に依存しないし、入力情報
が前回と一致しているかどうかというのを判定するのにまた時間がかかるだろう
から、キャッシュの同一性の判定は gawk で処理した後に行うべきの気がする。

* done: 後段の最も時間がかかっている部分について内容を確認する。bind -m xxx
'xxx' というのが約200行続いている。これについてキャッシュできないか考える
べきなのだろう。この時点での内容を何処かに保存しておいて…

% うーん。そもそも初期化の順序がどうなっているのか分からない。この関数の
% 呼び出しが初期化時の物であれば、この時点での keymap の状態は標準の状態
% になっていると考えられるので、"$settings" の内容だけでこれを eval した
% 後の状態が確定するのでキャッシュを読み込んで終わりにする事ができる。一
% 方で、別の場所から呼び出された時には、更に別の設定が keymap に加えられ
% ている可能性もあるので、不用意にキャッシュする事はできない。
%
% →という事を考えると初期化時の呼び出しの時だけキャッシュする様に、呼び
% 出し元から特別な opts を指定する等して区別しなければならない。
%
% もう一つの事はユーザー設定をキャッシュする為には emacs.sh 及び vi.sh を
% 読み込まなければならないという事である。そうすると keymap の遅延読み込
% みが全く為されなくなり意味がない。
%
% * うーん。bind の遅延には対応していたのだったか。もし bind の遅延に対応
% していたとすると更に話はややこしくなる。遅延した物を最後にひとつにま
% とめてその上でキャッシュするという様な仕組みにする必要が出てくる。然
% し、それは複雑すぎる様に思われる。
%
% →うーん。遅延されている。という事を考えると 0.7s かかっているのは実
% 際の ble-bind ではなくて、それをキャッシュする段階でかかっている時間
% という事になる。
%
% というかその前にそもそも遅延がどの段階で実装されているのかを確認する
% 必要がある→うーん。内部関数の ble-decode-key/bind の呼び出しがキャッ
% シュされている。この関数は decode 済みの keys 値と実際のコマンド名
% (ble/widget/xxxx など) を受け取っている。という事を考えると、時間がか
% かっているのは decode の部分なのだろう。
%
% * 元の標準設定が切り替わった時にはどうするのか。その時にもキャッシュを
% 更新しなければならない。

どうも時間がかかっているのは bind -m xxx yyy の yyy に含まれる keyseq
-> keys への翻訳の様に思われる。keymap は最初は初期化されていないと思わ
れるので、翻訳結果は全て ble-decode-key/bind の中でキャッシュされる。そ
のキャッシュ結果を何処かに保存しておけば良いという事になるのではないか。

翻訳過程をキャッシュしているので cmap 及び rlfunc 表の更新だけを気にし
ていればキャッシュの一貫性は保てる。

確認: 本当に初回呼び出しでは全ての keymap が未登録状態か? →実際にそうなっ
ている事を確認した。その条件が満たされている時にのみキャッシュを利用する
事にする。

取り敢えず実装した。動作確認した。inputrc を編集した時にちゃんと更新され
る事も確認した。

* done: 情報を集める箇所で ble/util/cat を3回実行している。これは readfile
か何かに置き換えるべきなのではないか。
→readfile に置き換えた。

* done: というか reconstruct のパイプを assign で分解したら 0.12s から
0.06s に短くなった。パイプは分解した方が良いのか…。

→分解した。

2021-09-21

* edit: set-mark 及び history-search-{for,back}ward を nmap で bind しようとしている [#D1651]
Expand Down
79 changes: 74 additions & 5 deletions src/decode.sh
Expand Up @@ -3739,20 +3739,22 @@ function ble/builtin/bind/initialize-inputrc {

# user 設定の読み込み
_ble_builtin_bind_user_settings_loaded=
function ble/builtin/bind/.reconstruct-user-settings {
local map q=\'
function ble/builtin/bind/read-user-settings/.collect {
local map
for map in vi-insert vi-command emacs; do
local cache=$_ble_base_cache/decode.readline.$_ble_bash.$map.txt
if ! [[ -s $cache && $cache -nt $_ble_base/ble.sh ]]; then
INPUTRC=/dev/null "$BASH" --noprofile --norc -i -c "builtin bind -m $map -p" |
LC_ALL= LC_CTYPE=C ble/bin/sed '/^#/d;s/"\\M-/"\\e/' >| $cache.part &&
ble/bin/mv "$cache.part" "$cache" || continue
fi
local cache_content
ble/util/readfile cache_content "$cache"

ble/util/print __CLEAR__
ble/util/print KEYMAP="$map"
ble/util/print __BIND0__
ble/bin/cat "$cache"
ble/util/print "${cache_content%$'\n'}"
if ((_ble_bash>=40300)); then
ble/util/print __BINDX__
builtin bind -m "$map" -X
Expand All @@ -3762,7 +3764,12 @@ function ble/builtin/bind/.reconstruct-user-settings {
ble/util/print __BINDP__
builtin bind -m "$map" -p
ble/util/print __PRINT__
done | LC_ALL= LC_CTYPE=C ble/bin/awk -v q="$q" -v _ble_bash="$_ble_bash" '
done
}
function ble/builtin/bind/.reconstruct-user-settings {
local collect q=\'
ble/util/assign collect ble/builtin/bind/read-user-settings/.collect
<<< "$collect" LC_ALL= LC_CTYPE=C ble/bin/awk -v q="$q" -v _ble_bash="$_ble_bash" '
function keymap_register(key, val, type) {
if (!haskey[key]) {
keys[nkey++] = key;
Expand Down Expand Up @@ -3847,14 +3854,76 @@ function ble/builtin/bind/.reconstruct-user-settings {
}
' 2>/dev/null # suppress LC_ALL error messages
}

## @fn ble/builtin/bind/read-user-settings/.cache-enabled
## @var[in] delay_prefix
function ble/builtin/bind/read-user-settings/.cache-enabled {
local keymap use_cache=1
for keymap in emacs vi_imap vi_nmap; do
ble/decode/keymap#registered "$keymap" && return 1
[[ -s $delay_prefix.$keymap ]] && return 1
done
return 0
}
## @fn ble/builtin/bind/read-user-settings/.cache-alive
## @var[in] settings
## @var[in] cache_prefix
function ble/builtin/bind/read-user-settings/.cache-alive {
[[ -e $cache_prefix.settings ]] || return 1
[[ $cache_prefix.settings -nt $_ble_base/lib/init-cmap.sh ]] || return 1
local keymap
for keymap in emacs vi_imap vi_nmap; do
[[ $cache_prefix.settings -nt $_ble_base/core-decode.$cache-rlfunc.txt ]] || return 1
done
local content
ble/util/readfile content "$cache_prefix.settings"
[[ ${content%$'\n'} == "$settings" ]]
}
## @fn ble/builtin/bind/read-user-settings/.cache-save
## @var[in] delay_prefix
## @var[in] cache_prefix
function ble/builtin/bind/read-user-settings/.cache-save {
local keymap content
for keymap in emacs vi_imap vi_nmap; do
if [[ -s $delay_prefix.$keymap ]]; then
ble/util/copyfile "$delay_prefix.$keymap" "$cache_prefix.$keymap"
else
: >| "$cache_prefix.$keymap"
fi
done
ble/util/print "$settings" >| "$cache_prefix.settings"
}
## @fn ble/builtin/bind/read-user-settings/.cache-load
## @var[in] delay_prefix
## @var[in] cache_prefix
function ble/builtin/bind/read-user-settings/.cache-load {
local keymap
for keymap in emacs vi_imap vi_nmap; do
ble/util/copyfile "$cache_prefix.$keymap" "$delay_prefix.$keymap"
done
}

function ble/builtin/bind/read-user-settings {
if [[ $_ble_decode_bind_state == none ]]; then
[[ $_ble_builtin_bind_user_settings_loaded ]] && return 0
_ble_builtin_bind_user_settings_loaded=1
builtin bind # inputrc を読ませる
local settings
ble/util/assign settings ble/builtin/bind/.reconstruct-user-settings
builtin eval -- "$settings"
[[ $settings ]] || return 0

local cache_prefix=$_ble_base_cache/decode.inputrc.$_ble_decode_kbd_ver.$TERM
local delay_prefix=$_ble_base_run/$$.bind.delay
if ble/builtin/bind/read-user-settings/.cache-enabled; then
if ble/builtin/bind/read-user-settings/.cache-alive; then
ble/builtin/bind/read-user-settings/.cache-load
else
builtin eval -- "$settings"
ble/builtin/bind/read-user-settings/.cache-save
fi
else
builtin eval -- "$settings"
fi
fi
}

Expand Down
13 changes: 10 additions & 3 deletions src/util.sh
Expand Up @@ -2048,9 +2048,10 @@ function ble/builtin/trap/install-hook {
##
if ((_ble_bash>=40000)); then
function ble/util/readfile { # 155ms for man bash
local __buffer
mapfile __buffer < "$2"
IFS= builtin eval "$1=\"\${__buffer[*]-}\""
local -a _ble_local_buffer=()
mapfile _ble_local_buffer < "$2"; local _ble_local_ext=$?
IFS= builtin eval "$1=\"\${_ble_local_buffer[*]-}\""
return "$_ble_local_ext"
}
function ble/util/mapfile {
mapfile -t "$1"
Expand All @@ -2070,6 +2071,12 @@ else
}
fi

function ble/util/copyfile {
local src=$1 dst=$2 content
ble/util/readfile content "$1" || return $?
ble/util/put "$content" >| "$dst"
}

## @fn ble/util/writearray [OPTIONS] arr
## 配列の内容を読み出し可能な形式で出力します。
##
Expand Down

0 comments on commit 994e2a5

Please sign in to comment.