Say I split a window into 2 panes, the right one has width 20 cells. But when I resize the outside terminal emulator, the pane's width changes.
Is there any way to fix this? Because I wanna display info which is formatted to fit for 20 cells
As far as I can tell, tmux does not have any settings for fixing the width to a minimum value, only to a max value. This is because terminal windows can be resized to smaller than tmux's min value and tmux may not have a suitable way of handling this.
That being said, if you have other tmux panes open, you could add a small script to PS1 (PS1='$(resizePane $id)other-stuff'
) or PROMPT_COMMAND in order to constantly resize the info-pane that you want to keep at 20c width as you use other panes within tmux. Essentially, 1) you can open the program, 2) resize the terminal, 3) move to another pane, 4) type Enter
and blam, the pane is resized.
You should look at the man pages for
resize-pane [-DLRU] [-t target-pane] [adjustment]
If you are in the desired pane, all that must be done is to shrink the width from the the left -L or from the right -R by x characters necessary to arrive at 20. Essentially, if the pane is up against a wall taller than the pane, use it's direction for shrinking and the opposite for enlarging. If my pane is next to the right wall, use -R to reduce the width and -L to enlarge it.
To get the right amount of characters, you need to know the current width of the pane, which can be found along with the pane id if you type
tmux list-panes
I am not yet sure of a way to tell which pane number you are currently in except by Prefix+q
or typing
tmux display-panes
This will give us the id number of all the panes in the current window. If we know the id# ($id) assuming it is against the right wall, we can resize the pane to 20 characters wide by:
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
Note that the resizeNum cannot be negative. If it is negative, then use the other side to resize to the absolute value of resizeNum (this can be automated, but I'll leave that up to you). Also, if you incorporate this into the code of your program, you can neglect the "-t $id" portion, but I do not know a way to automate finding $id from within your program.
It may also be of use for you to look at tmux setw main-pane-width
tmux setw other-pane-width
, which will set the specific pane width if you reload a new tile format. To cycle formats use Prefix+space
Hope this helps!
--- edited to add further info on automation ---
My previous thought, was for you to go to a new pane and run PS1="$(resizePane $id)${PS1}"
and then hit ENTER
within the other pane so that you can continue working in the newly resize pane, but I have considered a new option that may work for you ...
I have rethought this idea since originally posting and I think it can reasonably be automated if the program running has a loop that can send shell commands. This is because we can run the program by essentially splitting the window. Here is an example of what I mean. The following code
runCodeSplit.sh
, whichtest.sh
runCodeSplit.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"
test.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
NOTE: Unfortunately, the way I implemented it above, you should only really run it once per tmux window. The problem is that each time you run it, they will bunch up next to each other, which in turn will set them competing for space (one will shrink the other in order to expand and vice versa). You may be able to work around this problem, but I leave that up to you to figure out.
tmux display-message -p '#P'
Oct 25, 2013 at 11:52
I'll post my variety since it won't hurt anyone, and perhaps fits someone better as-is.
I use it to resize a pane in a irssi session inside tmux that reads the output from the nicklist.pl
script. The pane frequently gets resized when I attach over different terminals, and it is needed to be >20 columns wide for the FIFO to work correctly (and it's unnecessary to have it wider, stealing my screen space).
Ignore the convoluted CURRENT_PANE_WIDTH
calculation and use the grep+sed one instead if you want. The current one was mostly an experiment to keep the script entirely in shell (except the tmux calls, of course). It is most probably faster, which might be interesting for automation where the script runs frequently (I currently run it as a specific call, though).
#!/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
Since version 2.1, tmux supports hooks (grep the manual for ^HOOKS
). The example given in the manual (of the version 3.1, which I only have):
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"
The commands to execute when the hook triggering even happens are given to set-hook
in the same format as that used by bind-keys
.
In addition to the hooks listed in the HOOKS section, you can use all events described in the CONTROL MODE section (search the manual for ^CONTROL
). The hooks that you may use to resize panes when something interesting happens are client-resized
, pane-exited
and layout-change
(not "changed"!). Read on prefixing the hooks with the prefix after-
, as shown in the example cited above.
Different ways to refer to a pane which you can use with the resize-pane
command are listed in the COMMANDS section of the manual. Incomplete list includes pane numbers, offset numbers, and tokens like {top-right}
or {left-of}
. The command accepts absolute and relative sizes in character cells, and percentages of the window width.