完了関数から/dev/ttyを読む

完了関数から/dev/ttyを読む

次のコードがコマンドを完了できないのはなぜですかfoo?次のように入力すると、シェルがフリーズfoo <Tab>して押すまで^C(exitコマンドが完了します)、入力は許可されません。

私の仮定は、/dev/ttyシェルがそれを読み、それがcatそれを読む能力に何とか影響を与えるということです。ただし、この場合はまだ解決策が必要です。

_foo() {
    _values 'foo' "$(cat < /dev/tty)"
}

compdef _foo foo

この例は意図的に単純化されています。実際のユースケースは、非ターミナルインタフェースプログラム(ncursesを考えてみてください)を実行することですcat

答え1

完了時にzsh行エディタにあるので、次のようにターミナル行ルールの独自の行エディタが無効になります。

stty -icanon -echo

このモードでは、入力の終わり(行ルールの行エディタの動作の一部)を通知できず、入力した内容のエコーが表示されないため、cat終了する方法はありません。^Dicanon

次のことができます。

_foo() {
  _values 'foo' "$(
    {
      s=$(stty -g)
      stty sane
      cat
      stty $s
    } < /dev/tty)"
  zle -I
}

つまり、実行前にターミナルデバイスを期待したままにしてcat^D空白行を押すか、ダブルクリックして入力を終了できます)、cat実行後に復元します。私たちは、zleに、ラインルールラインエディタに入力したコンテンツのエコーが原因で混乱するので、プロンプトとバッファを再描画する必要があると言いますzle -I無効)。

答え2

これはおそらくとても簡単で、cat読むのに/dev/tty長い時間がかかります。_foo完成する

#compdef foo
_values 'foo' "$(promptfor)"

promptforそして

#!/usr/bin/env expect
set fh [open /dev/tty r+]
stty raw -echo
set key [read $fh 1]            ;# read from tty
puts stdout $key                ;# to ZSH
flush stdout
stty -raw echo

私のZSHは実行中に押すすべてのキーをfootab完了します。promptfor

ある種のデーモンがある場合は、ZSHやデーモンが必要な通信を実行するために使用できるソケットなど、よりエキゾチックなものが必要な場合があります。readZSHでは、任意のファイル記述子または補助プロセスから読み取ることができます。

関連情報