ncursesダイアログライブラリ(どこでも利用可能)を使用しようとしています。ソースミラーはこちら)、ダイアログボックスを使用するか、stdin / out / errがcharブロックデバイス、ttys、およびどのtermcapsに接続されているかによって、stderrとプロンプトで印刷するかどうかをコードで動的に決定します。私は less で正しくレンダリングできるかどうかを検出するのにかなり信頼できるコードを盗み、termcaps ce
、cd
、cl
and cm
、または を探して、そうho
でなければll
愚かなモードに切り替えます。ただし、lessの要件はダイアログボックスより低くなる可能性があります(多く?)(少なくともyesnoボックスのみが必要です)。ダイアログやncursesに大文字を確認せずに端末に問題を処理できるかどうか尋ねる方法がなく、大文字がないとinitscrが失敗することに少し驚きました。 Emacsシェルのダイアログボックス(ansi-termではなく、obvsではうまく機能します)は意味のないテキストだけを吐き出し、愚かな端末(通常のxtermと同じ)なので、ここで進む機能は明らかにありません。al
sr
export TERM=dumb
私はほとんどの場合UNIXプログラマーではありません。これを行う信頼できる標準的な方法はありますか?私を変に考えるのは、これが確認しやすいことではないということです。
明らかに、ダイアログを介してコードを書いて、それが呼び出すすべてのncursesエントリを記録しようとするかもしれませんが、それは痛いので、どこかで端末の機能要件の明確なリストを見つけることができないことを願っています。
修正する:だから私は「yesno」ダイアログをどれだけうまく得ることができるかをテストするために独自のカスタムterminfoエントリを作成することにしました。サイズが非常に小さいので、テストの数を減らす方が良いです。これを行う方法を理解するのは難しいです。したがって、THE FUTUREの他の人が簡単に要約した内容は次のとおりです。
- 以下はtermcap定義です。問題を特定する必要があります。 terminfo定義を使用していくつかの手順をスキップすることができますが、lessなどの古いソフトウェアはtermcapバージョンを使用しているため、そのスペースで作業する方が簡単です。
dialog --title Hi --yesno There 0 0
現在ターミナル(またはncurses)で実行されているncursesアプリケーションがあるとし、TERM envvarが何であるかを調べてください。私は画面とemacs ansi-termで作業しているので、もちろんテストscreen
中です。eterm-color
dumb
- 作業したいバージョンのダンプを使用します(新しいバージョンが作業バージョンのサブセットになりたいのでテストを実行しています)。
infocmp eterm > eterm2.info
これにより、そのバージョンで使用したい情報が提供されます。 - キャップに変えて
infotocap eterm2.info > eterm2.cap
- 内部を見て、次のように警告なしにほとんど実行されない最小限の制限ファイルであるかのように切り取ります。
# hacked eterm for testing dialog
eterm2|gnu emacs term.el terminal emulation:\
:am:mi:xn:\
:co#80:li#24:\
:ce=\E[K:cd=\E[J:cl=\E[H\E[J:\
:ho=\E[H:\
:cm=\E[%i%d;%dH:\
:al=\E[L:
- 最初は名前もeterm2に変更しました。
- 再び情報に変換
captoinfo eterm2.cap > eterm2.info
mkdir infodb
このテスト情報がコンパイルされるローカルディレクトリを作成します。export TERMINFO=$(pwd)/infodb
termcap / terminfoで見つけることができる場所を教えてください。tic -D
ローカルディレクトリを最初に出力する必要があります。tic -s eterm2.info
このディレクトリにコンパイルしてくださいexport TERM=eterm2
新しいハッカー端末の設定- ncurses アプリケーションを実行します。それ以外の場合は、
dialog --title Hi --yesno There 0 0
単に白黒で表示する必要があります。 - 他のコマンドを再度追加して変更を確認できますが、完了したらすべてが
rm -rf infodb
正しく実行されていることを確認してくださいexport TERMINFO=
。export TERM=<oldterm>
アップデート2: これは私が完成したコードであり、すべてのテストで動作するようです。
if(TermMode == TERM_UNINITIALIZED) {
struct stat s;
if((isatty(STDOUT_FILENO) && (fstat(STDOUT_FILENO,&s) == 0) && S_ISCHR(s.st_mode)) &&
(isatty( STDIN_FILENO) && (fstat( STDIN_FILENO,&s) == 0) && S_ISCHR(s.st_mode)))
{
// both stdout and stdin are char block device ttys, now check termcaps
// mostly stolen from the gnu less source code, since it seems robust
// https://github.com/gwsw/less/blob/22e4af5cccbfab633000c7d610f868a868ad6e1a/screen.c#L1280
char termbuf[2048];
char const* term = getenv("TERM");
int const TGETENT_OK = 1;
if(tgetent(termbuf,term) == TGETENT_OK) {
char sbuf[2048];
char* sp = sbuf;
char* sr = 0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
// ce ce cl are required
if((sr = tgetstr("ce",&sp)) && *sr && // eol clear
(sr = tgetstr("cd",&sp)) && *sr && // eos clear
(sr = tgetstr("cl",&sp)) && *sr) // screen clear
{
// cm or (ho and ll)
if(((sr = tgetstr("cm",&sp)) && *sr) || // cursor move
(((sr = tgetstr("ho",&sp)) && *sr) && // home
((sr = tgetstr("ll",&sp)) && *sr))) // lower left
{
// al or sr
if(((sr = tgetstr("al",&sp)) && *sr) || // add line
((sr = tgetstr("sr",&sp)) && *sr)) // scroll reverse
{
// we've got what we need for ncurses dialog!
TermMode = TERM_DIALOG;
goto term_detected;
}
}
}
#pragma GCC diagnostic pop
}
// we're at least connected to a tty
TermMode = TERM_STDIO;
} else {
// no interaction, so gotta just abort
TermMode = TERM_ABORT;
}
term_detected:
;
}
とにかく、最小のタンクキャップが何であるかを知ることはまだ良いですが、少なくとも上記のものは作業負荷を軽減するので使用します。
ありがとう、クリス