2016-05-11 11 views
6

私のコンピュータをよりよく理解し、ツールとして、私はmy own shellをC++で書いています。 Stephen Brennan's article on writing a simple shellは非常に役に立ちました。自分のシェルを書く:コマンド履歴をどのように実装するのですか?

しかし、私は、コマンド履歴をスクロールするために、上向き矢印キーと下向き矢印キーを押して処理する方法を誤解しています。

  • 私はncursesを試してみましたが、システム提供の殻がちょうどターミナルへの書き込み続けるように見えるのに対し、それは、画面全体を置き換えます。

  • 私はtcgetattrを使用して正準モードをオフにしましたが、入力時に矢印キーを押すと、テキストナビゲーションの左右矢印キーのすべての処理がオフになり、 Ctrl + C ... Ctr-Cに応答して自分自身で信号を送ることができますが、ターミナルでカーソルを戻す方法はわかりません(「戻る」を出力してスタートを書き換えるラインの)。また、私はXcodeの "ダム"ターミナルやMacのTerminal.appで動作しているかどうかによって、キーのエスケープシーケンスが異なるようです。

  • 私はfishシェルとbashのソースを見て、ちょうどそんなにが、私は関連する部分を見つけることができないということが起こっていることがあるようです。

どのように標準シェルがキー押しを受信するのですか?彼らはどのようにカーソルの移動とバックスペースを処理するのですか?彼らは画面を乗り越えることなくラインの一部をどのように書き直すのですか?シェルが何をする必要があるかを定義する標準がありますか?

PS - 前のコマンドを記録する方法を知っています。誰かがリターンを押してから、私が仕事に就くことができないのとは対照的に、彼らがタイプされている間、実際にキー押しを取得しています。

+1

使用[GNU readlineの](https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)または同等の[BSDのeditline](のhttp:// thrysoee.dk/editline/)。 –

+1

Close-voters:更新された質問を読んでいただければ幸いです。 –

+0

実際にどのように実装されているかわかりませんが、シェルが画面全体を書き換えているという疑いがありますncurses')。たとえば、 'bash'でC-lを押すと、画面全体が消去されます。これは、シェルが一度に1行を管理するだけではないことを示唆しています。私は 'readline'のようなライブラリも同様に端末全体を引き継ぐと思います。 –

答えて

1

ICANONECHOをオフにして、矢印キーのエスケープシーケンスを自分で解釈する必要があります。

画面に表示されているものとカーソルがある場所の "実際の"バッファを保持する必要があります。また、画面に必要なものとカーソルが必要な場所の「希望の」バッファが必要です。これらのバッファは、画面全体、プロンプトとユーザーの入力を含む行(ECHOを無効にしたため手動でエコーした)だけをカバーします。これらの行にすべてを印刷したので、あなたはその内容を知っています。

次の入力バイトを待つ直前に、目的のバッファに一致するように画面を更新します。戻る300(または9600)のボー接続では、印刷可能なバイトとターミナル制御シーケンスの最適なシーケンスを探して、実際のバッファを目的のバッファに変換することによって、この更新をできるだけ効率的にすることについて多くの注意を払っていました。最近では、最適であることはあまり重要ではありません。

これらのバッファは入力がラップするとラインに広がりますので、端末の幅を知り、トラッキングする必要があります(TIOCGWINSZSIGWINCHを使用)。行の折り返しではなく、水平スクロールで1行に固執することもできますが、端末の幅を知る必要があります。

termcapまたはterminfoデータベースの端末タイプ($TERM)を理論的に調べます。これは、ユーザーが特殊キー(矢印、ホーム、エンドなど)を押したときに期待されるエスケープシーケンスを示しています。)、カーソルを移動したり、画面の一部を消去したり、文字や行などを挿入したり、削除したりするエスケープシーケンスがあります。

最近では、特にホビープロジェクトではすべてがかなりxtermと互換性があります。

bashの場合、これはすべてGNU readlineライブラリで行われます。画面の更新(「再表示」と呼ばれる)はdisplay.cで行われます。入力エスケープデコードはinput.cで行われます。

しかし、コード例が必要な場合は、おそらくlinenoise(2000行以下)を見てください。これは、端末がVT100(したがってxterm)互換であることを前提としています。

も参照してください“Is there a simple alternative to Readline?”

関連する問題