1. ホーム
  2. command-line

[解決済み] Tmuxのペインタイトル

2022-12-29 11:08:37

質問

私のローカルマシンでは、3つのnode.jsインスタンスが同時に実行されています。それぞれは、"servers" と呼ばれる tmux ウィンドウ内の独自のペインを持っています。問題は、どのノードがどのペインで実行されているかを把握することがそれほど簡単ではないことです。

私が必要とするのは、各ペインに対するタイトルです。私が得たように、tmux 自体はこの機能を備えていません。すべての node.js インスタンスのすべてのペイン内で別々の tmux セッションを起動することは、過剰なことのように見えます。

では、コマンドを起動し、その出力を指定されたステータスバーでラップするような小さなプログラムはあるのでしょうか?

ありがとうございました。

どのように解決するのですか?

tmux はペイン単位のタイトルをサポートしますが、これらのタイトルを表示するペイン単位の場所は提供しません。

ペインのタイトルを設定するには、エスケープシーケンス ESC ]2; ... ESC \ (というセクションを参照してください)。 名前とタイトル の中にある tmux のマニュアルページを参照)。このようにシェルから行うことができます。

printf '\033]2;%s\033\\' 'title goes here'

各ペインのタイトルのデフォルトは、システムのホスト名です。デフォルトでは、アクティブなペインのタイトルは tmux のステータス行の右側に表示されます (セッション変数のデフォルトのグローバル値である status-right"#22T" %H:%M %d-%b-%y で、ペインのタイトル、時刻、日付の22文字が表示されます)。

したがって、アクティブなペインのタイトルを見ることができれば満足である限り (つまり、アクティブでないペインのタイトルを見るためにペインを切り替えても構わない場合)、デフォルトの機能で十分やっていくことができます。各ペインのメイン コマンドを開始する前に、適切なタイトル設定用エスケープ シーケンスを送信するだけです。


ペインごとの情報を表示するために専用の行がどうしても必要な場合は、ネストされた tmux

セッションは、最初に考えるほど (不必要な) 「やり過ぎ」ではないかもしれません。

一般的なケースでは、ある特定のターミナルで不可侵のステータス行を提供するために、元のターミナルと新しいターミナル (行数が 1 つ少ないもの) の間に位置する完全なターミナル (再) エミュレーターが必要になります。このような(再)エミュレーションは、内側の端末に送られた制御シーケンスを、元の端末用に変換するために必要である。たとえば、外側端末の下部にステータス行を維持するには、コマンド

最後の行に移動します。

内部端末に送られるのは

<ブロッククオート

次から最後の行に移動する。

に変換されて外部端末に送られた場合。同様に、内側の端末に送られるLFは、次のようにならなければならない。

<ブロッククオート

カーソルが最後から次の行にある場合、その行とその上のすべての行を 1 行上にスクロールし、明確な最後から次の行を提供する (最終行のステータス行を保護する)。 そうでなければ、LF を送信します。

を外部端末に送信します。

のようなプログラムは tmux スクリーン はまさにそのようなターミナル・リ・エミュレータです。確かに、ターミナル・エミュレータの周りには他の機能がたくさんありますが、単に 信頼性の高い ステータス ラインを提供するだけでも、ターミナル エミュレーションのコードの大きな塊が必要になります。


しかし、以下のように軽量なソリューションがあります。

  1. であれば、軽量な解決策となります。 Node.js インスタンス) が実行されているペインとのターミナルの相互作用が制限されており (つまり、カーソルの位置決めがない)、また
  2. プログラムの実行中にペインのサイズを変更しない。

多くのターミナル エミュレータのように tmux は、そのペインで "スクロール領域の設定" ターミナル制御コマンドをサポートしています。このコマンドを使用して、スクロール領域をターミナルの上部 (または下部) N-1 行に制限し、スクロールしない行に何らかのインスタンス識別テキストを書き込むことができます。

制限 (カーソル移動コマンドの許可なし、サイズ変更なし) が必要なのは、出力を生成するプログラム (たとえば <項目 Node.js インスタンス)は、スクロールが特定の領域に制限されていることを知らない。もし、出力を生成するプログラムがスクロール領域の外にカーソルを移動させた場合、出力は文字化けする可能性があります。同様に、端末エミュレータはおそらく端末のサイズが変更されたときに自動的にスクロール領域をリセットします (したがって、「スクロールしていない行」はおそらくスクロールしてしまいます)。

を使用するスクリプトを書きました。 tput を使って、適切な制御シーケンスを生成し、非スクロール行に書き込み、スクロール領域にカーソルを移動した後にプログラムを実行するスクリプトを書きました。

#!/bin/sh

# usage: no_scroll_line top|bottom 'non-scrolling line content' command to run with args
#
#     Set up a non-scrolling line at the top (or the bottom) of the
#     terminal, write the given text into it, then (in the scrolling
#     region) run the given command with its arguments. When the
#     command has finished, pause with a prompt and reset the
#     scrolling region.

get_size() {
    set -- $(stty size)
    LINES=$1
    COLUMNS=$2
}
set_nonscrolling_line() {
    get_size
    case "$1" in
        t|to|top)
            non_scroll_line=0
            first_scrolling_line=1
            scroll_region="1 $(($LINES - 1))"
            ;;
        b|bo|bot|bott|botto|bottom)
            first_scrolling_line=0
            scroll_region="0 $(($LINES - 2))"
            non_scroll_line="$(($LINES - 1))"
            ;;
        *)
            echo 'error: first argument must be "top" or "bottom"'
            exit 1
            ;;
    esac
    clear
    tput csr $scroll_region
    tput cup "$non_scroll_line" 0
    printf %s "$2"
    tput cup "$first_scrolling_line" 0
}
reset_scrolling() {
    get_size
    clear
    tput csr 0 $(($LINES - 1))
}

# Set up the scrolling region and write into the non-scrolling line
set_nonscrolling_line "$1" "$2"
shift 2

# Run something that writes into the scolling region
"$@"
ec=$?

# Reset the scrolling region
printf %s 'Press ENTER to reset scrolling (will clear screen)'
read a_line
reset_scrolling

exit "$ec"

こんな風に使うかもしれません。

tmux split-window '/path/to/no_scroll_line bottom "Node instance foo" node foo.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance bar" node bar.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance quux" node quux.js'

このスクリプトは tmux をサポートし、その csrcup terminfo 機能があります。