github.com/Yukaii
Daily Oops

Daily Oops!

https://yukai.dev/blog/2024/03/11/persistent-tmux-popup不會關掉的 tmux popuphttps://fed.brid.gy/
March 11, 2024

不會關掉的 tmux popup

追求極致的內建終端機體驗

在長期使用 neovim 之後,我發現 ToggleTerm 對我來說是最泛用靈活的工具。你可以:

  1. 拿來當輕量沒有 context switching 負擔的隨叫即用終端機
  2. 拿來綁定各種 TUI app,快速呼叫和隱藏

而 Astronvim 預設與 ToggleTerm 的鍵盤快速鍵,習慣後也覺得相當便利:

  • Ctrl + ' 快速開啟/隱藏終端機
  • 各種 TUI 綁定的快速鍵
  • Ctrl + l 隱藏 ToggleTerm

儘管如此,ToggleTerm 還是比不上 VSCode 內建終端機的功能:支援多個分頁快速切換,並且可以方便的綁定各種系統級的快速鍵。

使用 Tmux 重現 ToggleTerm 的體驗

至從我換到 Kakoune 後,我的編輯器肌肉記憶,最懷念的就是 ToggleTerm 的快速鍵。

很多時候我只是想要快速叫個終端機小視窗,而不想離開現有的畫面。此時 Popup 帶來的就是最少 Context switching 的體驗。而 Tmux 其實也已經內建了 popup 功能,只是:

  • 只能有單一視窗
  • 不能隱藏,開啟到程式結束為止

要做到永久維持的效果,直接建立一個 Tmux popup 專用的 session 就好啦!

tmux-poppup 腳本

#!/bin/bash
# Automatically fetch the current window ID and session name
window_id=$(tmux display-message -p '#I')
current_session_name=$(tmux display-message -p '#S')
# Fetch the current directory of the parent session
parent_session_dir=$(tmux display-message -p -F "#{pane_current_path}" -t0)
# Construct the unique session name with a "floating" suffix
session_name="floating_${current_session_name}_${window_id}"
startup_command="$1"
# Check if the floating popup session already exists
if tmux has-session -t "$session_name" 2>/dev/null; then
tmux popup -w 90% -h 80% -E "bash -c \"tmux attach -t $session_name\""
else
if [ -z "$startup_command" ]; then
# If no startup command is provided, just open a shell
tmux new-session -d -s "$session_name" -c "$parent_session_dir"
else
# If a startup command is provided, run it in the new session
tmux new-session -d -s "$session_name" -c "$parent_session_dir" "$startup_command"
fi
tmux popup -w 90% -h 80% -E "bash -c \"tmux attach -t $session_name\"" # Attach to the session in a popup
fi

然後在 .tmux.conf 增加以下:

bind "'" if-shell "[[ $(tmux display-message -p '#S') = floating* ]]" {
detach-client
} {
run-shell tmux-popup
}

可以看到 tmux-poppup 實作的地方,我在 session_name 的地方用了比較詳盡的 floating_${current_session_name}_${window_id} 的,這代表每個 window 開出來的 Popup session 都是不一樣的。如果你想讓單一個 session 共享 popup,把後面 window_id 拿掉即可。

最後附上影片。

24/03/14 更新

後來我又對腳本進行修改,現在支援啟動程式,如果既有 tmux session 已經有正在執行的程式,就會切換到那個 window,而不會重新啟動。比如說:tmux-popup lazygit 就會啟動 lazygit,即使再 detach 後,也會重新掛載該 lazygit window。

#!/bin/bash
# Automatically fetch the current window ID and session name
window_id=$(tmux display-message -p '#I')
current_session_name=$(tmux display-message -p '#S')
# Fetch the current directory of the parent session
parent_session_dir=$(tmux display-message -p -F "#{pane_current_path}" -t0)
# Construct the unique session name with a "floating" suffix
session_name="floating_${current_session_name}_${window_id}"
startup_command="$1"
# Check if the floating popup session already exists
if tmux has-session -t "$session_name" 2>/dev/null; then
if [ -n "$startup_command" ]; then
# If a startup command is provided, look for its process in the list of panes
target_pane=$(tmux list-panes -a -F "#{session_name} #{pane_id} #{window_name}" | grep -i "^$session_name" | grep -i "$(echo $startup_command | cut -d' ' -f1)" | awk '{print $2}')
switch_command=""
if [ -z "$target_pane" ]; then
# If the process is not found, create a new window with the startup_command in target session
window_name=$(echo $startup_command | cut -d' ' -f1)
tmux new-window -t "$session_name" -n "$window_name" -c "$parent_session_dir" "$startup_command"
else
# If the process is found, switch to that window
switch_command="tmux select-window -t $(tmux display-message -p -F "#{window_index}" -t"$target_pane") ;"
fi
fi
tmux popup -w 90% -h 80% -E "bash -c \"tmux attach -t $session_name; $switch_command\"" # Attach to the session in a popup
else
if [ -z "$startup_command" ]; then
# If no startup command is provided, just open a shell
tmux new-session -d -s "$session_name" -c "$parent_session_dir"
else
# If a startup command is provided, run it in the new session
window_name=$(echo $startup_command | cut -d' ' -f1)
tmux new-session -d -s "$session_name" -c "$parent_session_dir" "$startup_command"
tmux rename-window -t "$session_name":1 "$window_name"
fi
tmux popup -w 90% -h 80% -E "bash -c \"tmux attach -t $session_name\"" # Attach to the session in a popup
fi
https://fed.brid.gy/
本篇文章驕傲的使用 HackMD 發佈
Yukai Huanghttps://yukai.dev

Hi

This is Yukai Huang's personal website.

Here you can read my recent posts, play with my side projects before, or get to know me more.

安久吧!

https://fed.brid.gy/