From 0e16dbdb70717ebbc9ca4d9172c97a60c90fee7d Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Mon, 19 Jul 2021 14:58:08 +0900 Subject: [PATCH] edit: support "TMOUT" for the session timeout --- memo/ChangeLog.md | 1 + note.txt | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/edit.sh | 32 +++++++++++++++++++++++++++++ src/util.sh | 30 ++++++++++++++++++++++++++-- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/memo/ChangeLog.md b/memo/ChangeLog.md index 5476da64..6fe744f2 100644 --- a/memo/ChangeLog.md +++ b/memo/ChangeLog.md @@ -63,6 +63,7 @@ - prompt: support a new backslash sequence `\g{...}` `#D1609` be31391 - complete: add a new option `bleopt complete_limit_auto_menu` `#D1618` 1829d80 - rlfunc: support vi word operations in `emacs` keymap (requested by SolarAquarion) `#D1624` 21d636a +- edit: support `TMOUT` for the session timeout `#D1631` 0000000 ## Changes diff --git a/note.txt b/note.txt index b7fac32b..0a5386bc 100644 --- a/note.txt +++ b/note.txt @@ -4668,6 +4668,57 @@ bash_tips 2021-07-19 + * edit: support TMOUT for session timeout [#D1631] + + またそれと並行して session TMOUT についても実装したい。うーん。振る舞いにつ + いて確認する。恐らく最後にコマンドを実行してからどれだけ時間が経ったのかで + timeout を実行するという仕組みになっている。これはどの様に実装すれば良いの + だろうか。 + + 動作確認をして見た所、新しいコマンドを実行したタイミングというよりはやはり + accept をしたタイミング、或いは newline を挿入したタイミングでリセットされ + るという事の気がする。 + + 例えば insert-newline に於いてログアウト時刻をセットするという仕組みにする + のが良い気がする。ログアウト時刻が設定されていたらそれまで sleep するという + 事にする? 然し、それだと十分に長い timeout にしてたくさんコマンドを実行する + と、実行したコマンドの数だけ待ちタスクが増えて大変な事になってしまう。ユー + ザー入力または sleep で時間を測るというタスクが必要になる気がする。または、 + 後で外部からタスクの待ち時間を書き換える仕組みが必要になる気がする。 + + うーん。外部から既存のタスクの待ち時間を書き換える仕組みにするのが良い。 + + タスク番号を指定して書き換えられる様にする。その為にはタスク登録時に登録し + たタスクの番号が分かる様にするべきである。 + + ? それから bash-4.0 未満で idle.push が使えない場合にはどうするのか…? これ + は諦めるしかない様な気がする。bash-3.2 以下では TMOUT は動かない。 + + # 或いは bash-3.2 以下でも read -t 0 もしくは select に対応する様な物を + # loadable builtin 等で用意できればそれはそれで良いのかもしれないが、実の + # ところライセンスなどの問題から loadable builtin で実装するかどうかは悩 + # ましい所である。代わりに外部コマンドとして実装するという手もあるが。何 + # れにしてもこれは散々別の場所で議論してきた所であるから今ここでは議論し + # ない。 + + ? どのタイミングでタイマーをリセットするのが良いのか? insert-newline で実行 + しようかと考えていたが、insert-newline はコマンド実行前に実施される。本来 + はコマンド実行後にプロンプトが最初に表示された時点から実行するべきの様に + 思われる。 + + うーん。という事を考えると POSTEXEC で実行するべきだろうか。また、この場 + 合には一番最初のプロンプトに対して timeout が設定されないので、ble-attach + に際しても同様に設定をするべきの気がする。 + + POSTEXEC だと複数回のコマンドが実行される時に余分に timeout が再計算され + る事になる。それよりは /.end 辺りで設定した方が良いのではないかという気も + する。うーん。 + + 或いは、insert-newline で何か行番号等を更新して、PS1 の表示時にその行番号 + が変化していたら更新するという具合にするのが良い気がする。 + + 取り敢えず実装した。動いている。表示を多少調整した。 + * global: "TMOUT: readonly variable" というエラーメッセージが表示される (reported by farmerbobathan) [#D1630] https://github.com/akinomyoga/ble.sh/issues/129 diff --git a/src/edit.sh b/src/edit.sh index 6ae07c03..a23bba91 100644 --- a/src/edit.sh +++ b/src/edit.sh @@ -1370,6 +1370,36 @@ function ble/prompt/unit:_ble_prompt_status/update { #---------------------------------------------------------- # Update prompts for textarea +# process TMOUT +if ble/is-function ble/util/idle.push; then + _ble_prompt_timeout_task= + _ble_prompt_timeout_lineno= + function ble/prompt/timeout/process { + ble/util/idle.suspend # exit に失敗した時の為 task を suspend にする + _ble_edit_line_disabled=1 ble/widget/.insert-newline + ble/util/buffer.flush + ble/util/print "${_ble_term_setaf[12]}[ble: auto-logout]$_ble_term_sgr0 timed out waiting for input" + builtin exit 0 &>/dev/null + builtin exit 0 &>/dev/null + } >/dev/tty + function ble/prompt/timeout/check { + [[ $_ble_edit_lineno == "$_ble_prompt_timeout_lineno" ]] && return 0 + _ble_prompt_timeout_lineno=$_ble_edit_lineno + + if [[ ${TMOUT:-} =~ ^[0-9]+ ]] && ((BASH_REMATCH>0)); then + if [[ ! $_ble_prompt_timeout_task ]]; then + ble/util/idle.push -Z 'ble/prompt/timeout/process' + _ble_prompt_timeout_task=$_ble_util_idle_lasttask + fi + ble/util/idle#sleep "$_ble_prompt_timeout_task" $((BASH_REMATCH*1000)) + elif [[ $_ble_prompt_timeout_task ]]; then + ble/util/idle#suspend "$_ble_prompt_timeout_task" + fi + } +else + function ble/prompt/timeout/check { ((1)); } +fi + function ble/prompt/update/.has-prompt_command { [[ ${PROMPT_COMMAND[*]} ]] } @@ -1400,6 +1430,8 @@ function ble/prompt/update/.eval-prompt_command { function ble/prompt/update { local opts=:$1: dirty= + ble/prompt/timeout/check + # Update PS1 in PROMPT_COMMAND / PRECMD local version=$COLUMNS:$_ble_edit_lineno:$_ble_history_count if [[ $_ble_prompt_hash != "$version" && $opts != *:leave:* ]]; then diff --git a/src/util.sh b/src/util.sh index 56f79df6..97f200b1 100644 --- a/src/util.sh +++ b/src/util.sh @@ -4649,9 +4649,11 @@ if ((_ble_bash>=40000)); then ## C ## コマンド の実行結果が真になるのを待っているタスクです。 ## タスク内から ble/util/idle.wait-condition で設定します。 + ## Z + ## 停止中のタスクです。外部から状態を設定する事によって再開します。 ## _ble_util_idle_task=() - + _ble_util_idle_lasttask= _ble_util_idle_SEP=$_ble_term_FS ## @fn ble/util/idle.do @@ -4690,6 +4692,7 @@ if ((_ble_bash>=40000)); then (E) [[ -e ${_idle_status:1} ]] && _idle_to_process=1 ;; (P) ! builtin kill -0 ${_idle_status:1} &>/dev/null && _idle_to_process=1 ;; (C) builtin eval -- "${_idle_status:1}" && _idle_to_process=1 ;; + (Z) ;; (*) builtin unset -v '_ble_util_idle_task[_idle_key]' esac @@ -4819,13 +4822,14 @@ if ((_ble_bash>=40000)); then local i=$base while [[ ${_ble_util_idle_task[i]-} ]]; do ((i++)); done _ble_util_idle_task[i]=$entry + _ble_util_idle_lasttask=$i } function ble/util/idle.push { local status=R nice=0 while [[ $1 == -* ]]; do case $1 in (-[SWPFEC]) status=${1:1}$2; shift 2 ;; - (-[SWPFECIR]*) status=${1:1}; shift ;; + (-[SWPFECIRZ]*) status=${1:1}; shift ;; (-n) nice=$2; shift 2 ;; (-n*) nice=${1#-n}; shift ;; (*) break ;; @@ -4849,6 +4853,10 @@ if ((_ble_bash>=40000)); then function ble/util/is-running-in-idle { [[ ${ble_util_idle_status+set} ]] } + function ble/util/idle.suspend { + [[ ${ble_util_idle_status+set} ]] || return 2 + ble_util_idle_status=Z + } function ble/util/idle.sleep { [[ ${ble_util_idle_status+set} ]] || return 2 local ret; ble/util/idle.clock @@ -4900,6 +4908,24 @@ if ((_ble_bash>=40000)); then ble_util_idle_status=R } + function ble/util/idle/.delare-external-modifier { + local name=$1 + builtin eval -- 'function ble/util/idle#'$name' { + local index=$1 + [[ ${_ble_util_idle_task[index]+set} ]] || return 2 + local ble_util_idle_status=${_ble_util_idle_task[index]%%"$_ble_util_idle_SEP"*} + local ble_util_idle_command=${_ble_util_idle_task[index]#*"$_ble_util_idle_SEP"} + ble/util/idle.'$name' "${@:2}" + _ble_util_idle_task[index]=$ble_util_idle_status$_ble_util_idle_SEP$ble_util_idle_command + }' + } + # @fn ble/util/idle#suspend + # @fn ble/util/idle#sleep time + # @fn ble/util/idle#isleep time + ble/util/idle/.delare-external-modifier suspend + ble/util/idle/.delare-external-modifier sleep + ble/util/idle/.delare-external-modifier isleep + ble/util/idle.push-background 'ble/util/msleep/calibrate' else function ble/util/idle.do { false; }