‹ 指南

在手機上用 tmux

手機只有一塊螢幕,也沒有視窗管理員。tmux 讓你在一條連線裏開出好幾個,而鍵盤上方那排按鍵會自己變成 tmux 那一套。

撰寫於 · 更新於

一條連線,多個視窗

在電腦上,你會開三個終端機視窗並排擺着。手機上做不到:只有一塊螢幕,而且不大。看起來最順手的辦法(在 Term 裏多開幾個分頁),有個問題:每個分頁都是另一條連線,而連線恰恰就是手機鎖定螢幕、或者你在別的應用裏待久了之後會斷掉的東西。

tmux 的視窗才是答案:一條連線、一個工作階段,裏面想開幾個視窗就開幾個。一個跑建置,一個看日誌,一個開編輯器。切換只要一下,切走了也沒有任何東西會停。^Bc 新增視窗,^Bn 和 ^Bp 前後切換,^Bw 打開清單直接挑。這三個都在鍵盤上方那排按鍵裏,橫向滑動就能找到。

手機上執行 tmux:日誌在捲動,tmux 狀態列寫着 work | 1:build 2:logs 3:edit,下面的按鍵列是 ^B[ ^Bz ^Bc ^Bn ^Bp ^B%。
螢幕最下面那條是 tmux 自己的狀態列,也是這張地圖:work 是工作階段名稱,然後是 1:build 2:logs 3:edit,正在看的那個帶 *。再下面一排是 Term 的按鍵列,已經換成 tmux 那一套了。
tmux 的視窗清單覆蓋在工作階段上,列出三個視窗,其中一個反白。
^Bw:視窗清單。視窗多到不想一個個翻的時候用它,選中哪個就進哪個。

按鍵列會自己換

tmux 那套鍵不用你去開。Term 會看你前景在執行甚麼,然後把鍵盤上方那一排換成對應的:開了 tmux 就換成 tmux 的,退出來就換回去。它能知道,是因為你的 shell 會告訴它,也就是設定裏的「Shell 整合」,預設開着。同一條資訊在頂部導覽列也看得到:待在工作階段裏的時候,那裏寫的是 tmux attach -t work。

ctrlaltshifttab esc^B↑↓←→ ^B[^Bz^Bc^Bn^Bp ^B%^B"^Bo^Bw^Bd ^C^R

按鍵上的字是故意把整個組合拼出來的。一個標着 | 的鍵看上去像是打一個直線,但它不是,它是分割窗格。^B% 不會被看錯,而且它順便教會了你真正的按法,這個按法在你自己電腦上是一樣的。很多人第一次接觸 tmux 就是在手機上,手邊沒有速查表,這排按鍵就是速查表。不在這排裏的鍵,點最左邊的 ctrl 再按字母:它會為下一個按鍵加上 Ctrl,alt 和 shift 同理。

一張圖裏同時有:tmux 打出的「[detached (from session work)]」,以及下面已經換回普通 shell 那一套的按鍵列。
一張圖看清這次切換:^Bd 脫離的那一刻,tmux 打出 [detached (from session work)],下面那排按鍵已經換回 shell 的了。這中間不需要你設定任何東西。

分割窗格,以及為甚麼「放大」在這裏更重要

分割切的是你目前這個視窗:^B% 把新窗格放在旁邊,^B" 放在下面。然後手機就開始礙事了。預設字級下 Term 給你 56 欄,左右分割之後一邊 28 欄、一邊 27 欄,一條普通的日誌或者編譯錯誤,還沒說到重點就已經折了兩行。

手機上一個 tmux 視窗左右分成兩個窗格,每個約 28 欄寬,兩邊的文字都在詞中間折行。
一邊 28 欄。兩個窗格都運作得好好的,只是寬度不夠讓任何一邊讀着舒服。讀不了的分割,等於沒分。

^Bz 就是解法,而且它在手機上的價值遠高於在電腦上。它把你所在的窗格放大到整個視窗,同時版面原封不動,看完想看的,再按一次,分割還是剛才那個分割。手機上比較順手的用法是:需要來回切的用視窗,真的要同時盯着兩樣東西才用分割,並且讓其中一個保持放大。^Bo 切到下一個窗格,^B 之後接方向鍵則按方向切。

同一個分割,其中一個窗格放大到整屏,狀態列視窗名旁邊多了一個 Z。
同一個分割,放大之後。這個窗格拿回了完整的 56 欄。狀態列視窗名旁邊那個 Z,就是「這是放大的窗格」和「這個視窗本來就只有一個窗格」的分別。

回捲歷史 = 複製模式

進了 tmux 之後,拖動螢幕不再是捲動終端機,螢幕歸 tmux 管了。它的歷史在複製模式裏,^B[ 是入口;進去之後拖動即可捲動,也可以用按鍵列上的方向鍵,esc 離開。

這一點在 mosh 上最要緊:mosh 傳的是目前這一屏,不是一行行的位元組串流,所以它本身沒有歷史可供 Term 回捲,這是 mosh 的設計,不是應用的限制。在裏面執行 tmux,複製模式就是你的回捲區,能翻多遠由 history-limit 決定。

tmux 工作階段處於複製模式並已向上回捲,右上角顯示 [100/132]。
複製模式,角上那個計數就是你的位置:[100/132] 表示在一共 132 行的歷史裏往回翻了 100 行。

脫離與掛回

^Bd 脫離。你正在執行的東西全都留在伺服器上繼續跑(建置、日誌、編輯器裏還沒存的內容),之後 tmux attach -t work 把整個工作階段原樣接回來:一樣的視窗、一樣的分割、一樣的捲動位置。懶得記工作階段建過沒有的話,tmux new -A -s main 有就掛上、沒有就新建,很適合直接寫進主機的啟動腳本。

這正是 tmux 在手機上值得折騰的原因。切到背景後 Term 能撐住大約 90 秒,之後 HarmonyOS 就會暫停應用,連線也隨之關閉。但只要另一頭有 tmux,這一下甚麼都不會損失:你只是脫離了,不是被中斷了。

掛回之後的工作階段:還是那個分割,日誌仍在捲動。
掛回來了:還是那個分割,日誌還在跑,捲動位置也留着。工作階段這一側根本沒察覺手機離開過。

關於 mosh 的一點說明

走 SSH 的時候,Term 是靠 shell 回報的指令知道你前景在執行甚麼的。mosh 工作階段不會以同樣的方式回報指令,所以如果你用 mosh 連上去,再自己敲 tmux attach,工作階段本身跑得好好的,但按鍵列會停在 shell 那一套。ctrl 仍然可用,ctrl 再 b 再字母一樣能送出去,只是沒法一鍵完成。

透過 mosh 連上的一個真實 tmux 工作階段,下面卻是普通的 shell 按鍵列,不是 tmux 那一套。
mosh 裏的 tmux,配的是 shell 鍵。工作階段是真的(狀態列和視窗名都在),但下面這排是 shell 的。下面兩種辦法都只要改一行。

讓主機替你啟動 tmux

在主機的啟動腳本裏寫上 tmux new -A -s main。Term 會把啟動腳本一併算進它對這個工作階段的判斷裏,於是從第一格畫面開始就是 tmux 那排鍵,而且你一連上去就已經在工作階段裏了,不用再自己敲進去。

或者,把那個詞放進標題

Term 也會讀終端機標題,只要標題裏任何位置出現 tmux 這個詞就算數。下面那份設定裏寫的是 set-titles-string "#{pane_title}",得到的標題是 build 這樣的:裏面沒有 tmux 可找。改成 set-titles-string "tmux · #{pane_title}",不用動主機設定,mosh 下也能拿回 tmux 那排鍵。

這份應用實際用來測試的 tmux.conf:我們在用的 tmux 設定 · 常見問題:mosh + 多工器