如何使 tmux 的窗格宽度固定?

如何使 tmux 的窗格宽度固定?

假设我将窗口拆分为两个窗格,右侧窗格的宽度为 20 个单元格。但是当我调整外部终端仿真器的大小时,窗格的宽度会发生变化。

有什么办法可以解决这个问题吗?因为我想显示格式化为适合 20 个单元格的信息

答案1

据我所知,tmux 没有任何将宽度固定为最小值的设置,只有最大值。这是因为终端窗口可以调整为小于 tmux 的最小值,而 tmux 可能没有合适的方法来处理这种情况。

话虽如此,如果您打开了其他 tmux 窗格,则可以向 PS1 ( PS1='$(resizePane $id)other-stuff') 或 PROMPT_COMMAND 添加一个小脚本,以便在使用 tmux 内的其他窗格时不断调整信息窗格的大小,使其保持 20c 的宽度。本质上,1) 您可以打开程序,2) 调整终端大小,3) 移动到另一个窗格,4) 键入Enter并砰的一声,窗格就调整大小了。

你应该看看

resize-pane [-DLRU] [-t target-pane] [adjustment]

如果您位于所需的窗格中,则必须执行的所有操作都是将宽度从左侧 -L 或从右侧 -R 缩小 x 个字符,以达到 20。本质上,如果窗格靠在比窗格高的墙上,则使用其方向进行缩小,反之则进行放大。如果我的窗格紧挨着右墙,则使用 -R 减小宽度并使用 -L 放大它。

要获取正确数量的字符,您需要知道窗格的当前宽度,如果您输入,可以与窗格 ID 一起找到它

tmux list-panes

除了通过Prefix+q或输入

tmux display-panes

这将为我们提供当前窗口中所有窗格的 ID 号。如果我们知道 id# ($id) 并假设它靠在右墙上,我们可以通过以下方式将窗格的大小调整为 20 个字符宽:

paneWidths=$(tmux list-panes | awk '{print $2}' | cut -c 2- | cut -f 1 -d'x')
currentWidth=$(echo $paneWidths | sed $id'q;d')
resizeNum=$(expr $currentWidth - 20)

tmux resize-pane -R -t $id $resizeNum

请注意,resizeNum 不能为负数。如果为负数,则使用另一边调整大小为 resizeNum 的绝对值(这可以自动完成,但我将把这留给您自己决定)。此外,如果您将其合并到程序代码中,则可以忽略“-t $id”部分,但我不知道如何在程序中自动查找 $id。

您可能还需要查看tmux setw main-pane-width tmux setw other-pane-width,如果您重新加载新的图块格式,它将设置特定的窗格宽度。要循环格式,请使用Prefix+space

希望这可以帮助!

--- 编辑以添加有关自动化的更多信息 ---

我以前的想法是,让您转到一个新窗格并运行PS1="$(resizePane $id)${PS1}",然后点击ENTER另一个窗格,以便您可以继续在新调整大小的窗格中工作,但我已经考虑了一个可能适合您的新选项......

自从最初发布以来,我重新考虑了这个想法,我认为如果运行的程序有一个可以发送 shell 命令的循环,那么它可以合理地实现自动化。这是因为我们可以通过本质上分割窗口来运行程序。下面是我所指的一个例子。以下代码

  1. 用户runCodeSplit.sh运行
  2. 在最后一个窗格的右侧水平拆分一个新窗格(20c 宽度),并运行test.sh
  3. 进入循环
  4. 检查当前窗格大小并尝试调整大小
  5. 休眠 10 秒(但你可以根据需要更改此时间)
  6. 重复 3 和 4 10 次,然后退出

运行CodeSplit.sh:

#!/bin/bash
# runCodeSplit.sh

paneID=$(tmux list-panes | wc -l)
echo "pane: $paneID"
echo $(expr $paneID - 1)

# now, open a new pane and run the func
tmux split-window -h -l 20 -t $(expr $paneID - 1 ) "~/test.sh $paneID"

测试.sh:

#!/bin/bash
# test.sh
if [[ $# -lt 1 ]] ; then 
    echo "please provide the pane-number" 
    exit 
fi
paneID=$1
i=0
while [[ i -lt 10 ]] ; do
    # find the current width and resize it at every loop
    width=$(tmux list-panes | awk '{print $2}' | cut -c 2- | cut -f 1 -d'x' | sed $(expr $paneID + 1)'q;d')
    resizeNum=$(expr $width - 20)
    echo "$paneID : w $width     r $resizeNum"

    if [[ $resizeNum -gt 0 ]] ; then
        tmux resize-pane -R -t $paneID $resizeNum
    elif [[ $resizeNum -lt 0 ]] ; then
        tmux resize-pane -L -t $paneID $(expr 0 - $resizeNum)
    fi 

    #now, we can do stuff ... 
    let i++
    echo "i= $i / 10"
    sleep 10
done
read -p "Press any key to close this pane ... " -n1 -s

笔记:不幸的是,按照我上面的实现方式,您实际上只能在每个 tmux 窗口中运行一次。问题是,每次运行它时,它们都会挤在一起,这反过来又会导致它们争夺空间(一个会缩小另一个以扩大空间,反之亦然)。您也许可以解决这个问题,但我留给您自己去解决。

答案2

我会发布我的版本,因为它不会伤害任何人,并且可能更适合某些人。

我使用它来调整 tmux 中 irssi 会话中窗格的大小,该会话读取来自nicklist.pl脚本。当我连接到不同的终端时,窗格经常会调整大小,并且它需要>20列宽才能使FIFO正常工作(并且没有必要让它更宽,这会占用我的屏幕空间)。

忽略复杂的CURRENT_PANE_WIDTH计算,如果需要,可以使用 grep+sed 来代替。当前版本主要是将脚本完全保留在 shell 中的实验(当然,tmux 调用除外)。它很可能更快,这对于脚本频繁运行的自动化来说可能很有趣(不过,我目前将其作为特定调用运行)。

#!/bin/sh
TMUX="/usr/bin/tmux"
TMUX_SESSION="irssi"
TMUX_WINDOW="0"
TMUX_WINDOW_PANE="1"
DESIRED_PANE_WIDTH="20"

error()
{
    printf '%s: error: %s\n' "${0##*/}" "${1}" 1>&2
    exit ${2}
}

# Find with grep and sed. More readable and easier to modify.
#CURRENT_PANE_WIDTH="$(${TMUX} list-panes -t "${TMUX_SESSION}:0 | grep "^${TMUX_WINDOW_PANE}: " | sed 's/^'"${TMUX_WINDOW_PANE}"': \[\([^x]\+\).*/\1/')"

# Find with shell expansion. Because it can be done!
CURRENT_PANE_WIDTH=$(${TMUX} list-panes -t "${TMUX_SESSION}:${TMUX_WINDOW}" |\
while read line; do
    PANE_MATCH="${line#${TMUX_WINDOW_PANE}:\ \[}"
    if [ "${line}" != "${PANE_MATCH}" ]; then
        CURRENT_PANE_WIDTH="${PANE_MATCH%%x*}"
        printf "${PANE_MATCH%%x*}"
        break;
    fi
done)

if [ -z "${CURRENT_PANE_WIDTH}" ]; then
    error 'no matching pane found.' 1
fi

if ! [ "${CURRENT_PANE_WIDTH}" -eq "${CURRENT_PANE_WIDTH}" ]; then
    error 'could not get integer width.' 1
elif ! [ "${CURRENT_PANE_WIDTH}" -eq "${DESIRED_PANE_WIDTH}" ]; then
    RESIZE_NUMBER=$((${CURRENT_PANE_WIDTH} - ${DESIRED_PANE_WIDTH}))
    if [ ${RESIZE_NUMBER} -ge 0 ]; then
        DIRECTION="R"
    else
        DIRECTION="L"
        RESIZE_NUMBER=$((-${RESIZE_NUMBER}))
    fi

    ${TMUX} resize-pane -t "${TMUX_SESSION}:${TMUX_WINDOW}" -${DIRECTION} ${RESIZE_NUMBER}
fi

答案3

从 2.1 版开始,tmux 支持钩子(在手册中查找^HOOKS)。手册中给出了示例(我只有 3.1 版):

A command's after hook is run after it completes, except when the command is run as part of a hook
itself.  They are named with an ‘after-’ prefix.  For example, the following command adds a hook to
select the even-vertical layout after every split-window:

      set-hook -g after-split-window "selectl even-vertical"

当钩子触发时执行的命令与set-hook使用的格式相同bind-keys

除了 HOOKS 部分列出的钩子之外,您还可以使用 CONTROL MODE 部分中描述的所有事件(在手册中搜索^CONTROL)。在以下情况下,您可以使用以下钩子来调整窗格大小:有趣的事情发生的事情是client-resizedpane-exitedlayout-change(不是“改变”!)。继续阅读,在钩子前加上前缀after-,如上面引用的示例所示。

resize-pane手册的“命令”部分列出了可用于该命令的引用窗格的不同方法。不完整的列表包括窗格编号、偏移编号和类似{top-right}或 的标记{left-of}。该命令接受字符单元格中的绝对和相对大小以及窗口宽度的百分比。

相关内容