2

I have 6 panes open in a tmux window.

Prefix:select-layout tiled arranges them as such:

+---------+---------+
|    1    |    2    |
+---------+---------+
|    3    |    4    |
+---------+---------+
|    5    |    6    |
+---------+---------+

That's nice, but my monitor is wide and short, and for the processes I'm running it's a huge waste of horizontal space.

I'd much rather arrange them as such:

+-----+-----+-----+
|  1  |  2  |  3  |
+-----+-----+-----+
|  4  |  5  |  6  |
+-----+-----+-----+

Assuming that the numeric ordering of the panes themselves doesn't matter, and crucially without stopping any of my running processes, how can I switch from the first layout to the second?

2
  • I recreated the upper layout. If I move the line between 3 and 4, other lines are unaffected. If I move the line between 1 and 3, it takes the line between 2 and 4 with it; you can call them a single long horizontal line. This raises a question: in the lower layout, do you want the horizontal or vertical lines to be "screen long"? Or maybe you don't care? Apr 20, 2020 at 9:41
  • @KamilMaciorowski Me personally, I don't care - I have no plans on disturbing this balanced layout. I suppose having the vertical lines be "screen long" would be slightly preferable, if only so that I could have a full vertical panel show my top in the case that I'm able to drop a pane. Apr 20, 2020 at 10:57

2 Answers 2

2

You can use tmuxlayout which is a perl script where you would just run, in another window, tmuxlayout 123 456 and it would send the appropriate commands to the running tmux.

It could be a bit hard to install as it may not be in a repository for your distribution.


If you want to install tmuxlayout locally, without being root or messing up your /usr/lib and so on, you can do so after installing the cpan command, which should be in your repository.

You can then run cpan interactively as shown below with only 3 lines of input. It will create only 2 directories in your $HOME: perl5/ and .cpan.

In the following I've removed the copious output, so simply press return when asked to configure automatically yes, press return when asked to choose local::lib, then type the command install Term::Tmux::Layout.

$ cpan
Would you like to configure as much as possible automatically? [yes] 
What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib] 
cpan[1]> install Term::Tmux::Layout

If it said the install was OK, at the next prompt type control-D to exit, and note the values it asks you to set:

cpan[2]> ^D
*** Remember to add these environment variables to your shell config
and restart your shell before running cpan again ***
PATH="/home/meuh/perl5/bin${PATH:+:${PATH}}"; export PATH;
PERL5LIB="/home/meuh/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
PERL_LOCAL_LIB_ROOT="/home/meuh/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT="--install_base \"/home/meuh/perl5\""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/home/meuh/perl5"; export PERL_MM_OPT;

Create a small shell script with the above 5 lines, and add at the end

tmuxlayout 123 456

and run the script.

3
  • Seems like the perfect solution in theory - sadly I have no idea how to install this, especially without root. perl is a whole new world to me and it's not a world I can just justify spending much time exploring, sorry! But thank you for your answer! Apr 20, 2020 at 12:05
  • 1
    I've added the info on how to use cpan to install the command in your home directory.
    – meuh
    Apr 20, 2020 at 12:24
  • Thank you!! I did manage to get to the install Term::Tmux::Layout stage but was met with permission errors - I must have messed up the initial config because I then ran o conf init to redo it and the second install worked fine. This solution is disgustingly overcomplicated but it does work and you have my eternal gratitude. Apr 20, 2020 at 15:13
3

I wrote the below script to easily place panes in a grid. It uses a function from Sleep_Walker's blog. It's unclear to me what the licence is. To be on the safe side I removed the function from my code and posted it separately as a proper citation.

You need to compose the full script by pasting the function into the script.

#!/bin/bash

# number of rows
m="$2"
# number of columns
n="$1"

target="${3:-$TMUX_PANE}"
set -- $(tmux list-panes -t "$target" -F '#{pane_id}')

n="${n:-$(($#/m))}"
m="${m:-$(($#/n))}"

if [ "$#" -ne "$((m*n))" ]; then
    printf '%s: panes needed for %sx%s layout: %s; panes detected: %s. Aborting.\n' "$0" "$n" "$m" "$((m*n))" "$#" >&2
    exit 1
fi

if [ "$m" -eq 1 ]; then
   layout=even-horizontal
elif [ "$n" -eq 1 ]; then
   layout=even-vertical
else

# ---------- IMPORTANT ----------
# Visit http://sleepwalker-hnd.blogspot.com/2016/07/tmux-layout-checksum.html
# and paste tmux_layout_checksum function here.

   create_row() {
      row="${n}x1,0,${1}{"
      shift
      for j in $(seq 0 "$((n-1))"); do
         row="${row}1x1,${j},0,${1#%},"
         shift
      done
      row="${row%,}},"
   }

   layout="${n}x${m},0,0["
   for i in $(seq 0 "$((m-1))"); do
      create_row "$i" "$@"
      shift "$n"
      layout="${layout}${row}"
   done
   layout="${layout%,}]"
   layout="$(tmux_layout_checksum "$layout"),${layout}"

fi

tmux select-layout -t "$target" "$layout"

The mentioned function:

tmux_layout_checksum() {
    local layout="$1"
    local csum=0
    local i
    for i in $(seq 0 $((${#layout} - 1))); do
        let csum=$(((csum >> 1) + ((csum & 1) << 15)))
        let csum=$((csum + $(LC_CTYPE=C printf '%d' "'${layout:$i:1}")))
    done
    printf '%x' "$((csum & 0xffff))"
}

Source: Sleep_Walker's blog.


Usage

Let's assume you named the script tmux-grid. The usage is:

tmux-grid columns [rows [target]]

target is exactly what tmux … -t expects. With it you can target any tmux window. If omitted or empty, $TMUX_PANE will be used. This way you don't need target to change the layout of the current window from within the window itself.

rows is the desired number of rows. If omitted or empty, the script will try to calculate this number from the number of existing panes and specified columns.

columns is the desired number of columns. If empty, the script will try to calculate this number from the number of existing panes and specified rows.

In your case invoke one of these from within one of the 6 panes in question:

tmux-grid 3      # exactly 3 columns
tmux-grid '' 2   # exactly 2 rows
tmux-grid 3 2    # exactly 3 columns and exactly 2 rows

Note in general tmux-grid 2 needs an even number of panes; tmux-grid 3 needs the number to be divisible by 3; tmux-grid 3 2 needs exactly 6 panes.

If each pane is busy, you can invoke the command from another window. In this case you need to specify target. This may be handy:

tmux-grid 3 '' {marked}

(For users not familiar with the concept of marked pane: this another answer of mine.)


How it works

The script builds a layout of panes of the size 1x1 each. Thanks to the fact tmux select-layout recalculates the layout to match the window size, the panes are resized automatically.

Note: my later tests succeeded with panes of the size 0x0. I kept the original script though.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .