为 tmux 创建“焦点模式”?(一个居中的窗格两侧是两个空白窗格?)

为 tmux 创建“焦点模式”?(一个居中的窗格两侧是两个空白窗格?)

我想使用 tmux 为终端创建一个“焦点模式”,有点像goyo 为 vim 做了什么

goyo 截图

问题 1:调整窗格大小

我的想法是通过将窗口分成三个窗格来实现这一点,然后将中心窗格设置为固定的最大值(可能是 80 列?可能是 100 列?可能根据终端窗口大小设置不同的最大值,例如响应式 Web 布局?)并将侧窗格设置为均匀填充剩余的列。我还希望它能够在不同尺寸的屏幕上工作,以便我可以在笔记本电脑和台式机上使用它。

目前,我能想到的唯一办法就是与 shell 合作(IE,使用 获取终端宽度tput cols,然后使用 进行数学运算计算每个窗格所需的宽度$(())。我对此没意见,但如果在 tmux 中有一个内置方法来实现这一点,我会因为错过它而感到非常愚蠢。

那么...有吗?

问题 2:遮挡侧窗格

这不是那么重要;看到一个几乎空白的窗格顶部有一个提示符真的不是那么糟糕。我知道 tmux 有clock-mode(例如),它会覆盖窗格的内容并显示其他内容。所以我想知道是否有办法完全隐藏非活动窗格的内容。到目前为止,我能想到的最好的办法是将 fg 和 bg 设置为相同的颜色

:select-pane -t:.1 -P 'fg=black,bg=black'

或者圣杯

如果有设施,这一切都可以更容易地实现边距在 tmux 的窗格上。据我所知,此功能不存在,但我远不是 tmux 专家。有没有可能它就在那里,而我只是不知道?

答案1

这就是我的名字_tmux-margins

#!/bin/sh

pane="${2:-$TMUX_PANE}"
[ -n "$pane" ] || exit 1
tmux has-session -t "$pane" 2>/dev/null || exit 0

tool="$0"
width="${TMUX_M_COLUMNS:-80}"
step=10
todo="${TMUX_M_COMMAND:-true}"
action="$1"
pattern=" '$tool' sleep "
pattern_left="$pattern'${pane}' left"
pattern_right="$pattern'${pane}' right"
command_left="TMUX_M_COMMAND='$todo'$pattern_left"
command_right="TMUX_M_COMMAND='$todo'$pattern_right"

tmux display-message -p '#{pane_start_command}' | grep -qF "$pattern" && exit 0

find_margins() {
    pane_left="$(tmux list-panes -F "#{pane_id} #{pane_start_command}" | grep -F "$pattern_left" | head -n 1 | cut -d ' ' -f 1)"
    pane_right="$(tmux list-panes -F "#{pane_id} #{pane_start_command}" | grep -F "$pattern_right" | head -n 1 | cut -d ' ' -f 1)"
}

find_geometry() {
    [ -n "$pane_left" ] && width_left="$(tmux display-message -p -t "$pane_left" '#{pane_width}')" || width_left=0
    [ -n "$pane_right" ] && width_right="$(tmux display-message -p -t "$pane_right" '#{pane_width}')" || width_right=0

    border=0
    [ "$width_left" -gt 0 ] && border=$((border+1))
    [ "$width_right" -gt 0 ] && border=$((border+1))

        width_center="$(tmux display-message -t "$pane" -p '#{pane_width}')"
    width_all="$((width_center+width_left+width_right+border))"

    [ "$((width+5))" -ge "$width_all" ] && width="$width_all"
}

destroy() {
    [ -n "$pane_left" ] && [ "$pane_left" != "$TMUX_PANE" ] && tmux kill-pane -t "$pane_left"
    [ -n "$pane_right" ] && [ "$pane_right" != "$TMUX_PANE" ] && tmux kill-pane -t "$pane_right"
    [ "$pane_left" = "$TMUX_PANE" ] || [ "$pane_right" = "$TMUX_PANE" ] && tmux kill-pane -t "$TMUX_PANE"
    true
}


create() {
    width_left=$(( (width_all-width-2)/2 ))
    [ "$width_left" -gt 2 ] || width_left=2
    if [ -n "$pane_left" ]; then
        tmux resize-pane -t "$pane_left" -x "$width_left"
    else
        tmux split-window -hdbl "$width_left" -t "$pane" "$command_left"
    fi

        width_right=$(( width_all-width-width_left-2 ))
        [ "$width_right" -gt 2 ] || width_right=2
    if [ -n "$pane_right" ]; then
        tmux resize-pane -t "$pane_right" -x "$width_right"
    else
        tmux split-window -hdl "$width_right" -t "$pane" "$command_right"
    fi
}

equalize() {
        width="$width_center"
    [ "$width" -lt "$width_all" ] && create
}

verify() {
    tmux has-session -t "$pane" 2>/dev/null || destroy
}

resize() {
    width="$((width_center${1}))"
    if [ "$((width+5))" -ge "$width_all" ]; then
        destroy
    else
        create
    fi
}

main() {
    find_margins
    find_geometry
    case "$action" in
        sleep )
            trap destroy INT
            trap 'verify; kill "$!" 2>/dev/null; $todo &' WINCH
            while true; do
                $todo &
                while sleep 1; do verify; done
            done
        ;;
        ""|c* )
            create
        ;;
        d* )
            destroy
        ;;
        e* )
            equalize
        ;;
        + )
            resize "+$step"
        ;;
        - )
            resize "-step"
        ;;
        +*|-* )
            resize "$action"
        ;;
    esac
}

main

有些部分和解决方案我并不满意。但它仍然有效。


像这样使用它(假设它位于您的目录中$PATH):

  • 要创建边距:
    • _tmux-margins c
    • 或者_tmux-margins create
    • _tmux-margins cwhatever(实际上以 开头的任何内容c
    • _tmux-margins(创建是默认操作)。
  • 销毁边距:
    • _tmux-margins d(实际上任何以: d,,,del开头的delete内容)。destroydwhatever
  • 要均衡边距宽度:
    • _tmux-margins e(事实上​​任何以 开头的事物e)。
  • 要放大中心窗格(缩小边距):
    • _tmux-margins +
    • _tmux-margins +NN如果可能的话,将列添加到中心窗格)。
  • 缩小中心窗格(扩大边距):
    • _tmux-margins -
    • _tmux-margins -NN如果可能的话,从中心窗格中减去列)。

第二个参数(上例中未使用)指定窗格。这样,您可以从另一个窗格或从 外部调用该工具tmux。示例:

_tmux-margins c .1
_tmux-margins - %5

有两个有用的变量:

  • TMUX_M_COLUMNS– 创建边距时中心窗格的所需宽度(80如果未设置)。
  • TMUX_M_COMMAND– 在边距窗格中运行的命令(true如果未设置)。如果调整了边距大小,命令将重新启动。我实现此功能的主要原因是:

    TMUX_M_COMMAND='cmatrix -u 20' _tmux-margins create
    

我的里面有这个~/.tmux.conf

bind-key -T root C-Up    run-shell -b 'TMUX_PANE="#{pane_id}" _tmux-margins d "#{pane_id}"'
bind-key -T root C-Down  run-shell -b 'TMUX_PANE="#{pane_id}" _tmux-margins c "#{pane_id}"'
bind-key -T root C-Left  run-shell -b 'TMUX_PANE="#{pane_id}" _tmux-margins - "#{pane_id}"'
bind-key -T root C-Right run-shell -b 'TMUX_PANE="#{pane_id}" _tmux-margins + "#{pane_id}"'

这些行使Ctrl+ Ctrl+ Ctrl+Ctrl+分别调用_tmux-margins d… c和,… -… +当前窗格为目标。

笔记:

  • 这些组合键对我来说在 Linux 本地和从sshLinux 到 Linux 都有效。当我在 Windows 上使用 PuTTY 连接到 Linux 时,它们对我不起作用。我还没有尝试修复此问题。也许可以配置 PuTTY 使其工作,我不知道。无论如何,您可以选择其他组合,可能使用前缀键 ( bind-key -T prefix …)。
  • _tmux-margins e如果您发现有用的话,请继续绘制地图。
  • 通过按键调用的脚本无法访问当前窗格中的 shell 环境(比较这个答案)。这意味着为了使用TMUX_M_COLUMNSTMUX_M_COMMAND按键,您需要为 tmux 服务器本身设置它们:

    • 对于第一个tmux(启动服务器的那个):

      TMUX_M_COMMAND='cmatrix -b' tmux
      
    • 或者在你的~/.tmux.conf

      set-environment -g TMUX_M_COMMAND 'cmatrix -b'
      

      (注意-g(全局环境)是必须的,因为tmux.conf它在任何会话开始之前进行解析);

    • 或更高版本(当 tmux 服务器正在运行时)如下所示:

      tmux set-environment TMUX_M_COMMAND 'cmatrix -b'
      

      (有或没有-g;注意如果不在 tmux 内,那么您需要-g-t);

    • 或者从 tmux 内部:

      prefix:set-environment TMUX_M_COMMAND 'cmatrix -b'Enter

      (再次强调,有或没有-g)。


一般注意事项:

  • 边距只是窗格。如果您拆分边距或将其与另一个窗格交换或将其从窗口中分离出来,使其看起来不像一个合适的边距,那么这就是您的问题。或者如果您拆分中心窗格等。
  • 另一方面,您可以像任何其他窗格一样调整边距的大小(可以使用鼠标);这_tmux-margins e很有用。
  • 我的脚本尝试不为边距创建边距。
  • 销毁一个边距会销毁另一个边距。您可以选择一个边距并点击Ctrl+ c,而不是调用_tmux-margins d
  • 销毁窗格会销毁其边距(如果存在)。

相关内容