Pane Title in Tmux
Asked Answered
S

11

134

On my local machine I've got 3 node.js instances running simultaneously. Each has it's own pane in a tmux window called "servers". The problem is that it's not that easy to figure out which node is running in which pane, 'cause their logs are similar.

What I need is a title for every pane. As I got, tmux itself doesn't have the feature: it has only titles for windows and not for panes. Launching a separate tmux session inside every pane for every node.js instance looks like an overkill.

So is there some small program that launches a command, wrapping its output with a specified status bar?

Spaceless answered 17/3, 2012 at 6:46 Comment(1)
tmux as of version 2.3 supports pane titles, see https://mcmap.net/q/167274/-pane-title-in-tmuxMainland
B
96

tmux does support per-pane titles, but it does not provide a per-pane location to display these titles.

You can set a pane’s title with the escape sequence ESC ]2; … ESC \ (e.g. see the section called Names and Titles in the tmux manpage). You could do this from the shell like this:

printf '\033]2;%s\033\\' 'title goes here'

Each pane’s title defaults to the system’s hostname. By default the active pane’s title is displayed on the right side of the tmux status line (the default global value of the session variable status-right is "#22T" %H:%M %d-%b-%y, which shows 22 characters of the pane’s title, the time, and the date).

So, as long as you are satisfied with being able to see the active pane’s title (i.e. willing to switch panes to see the title of an inactive pane), you can get by with the default functionality. Just send the appropriate title-setting escape sequence before starting the main command for each pane.


If you absolutely need a dedicated line to display some per-pane information, then nested tmux sessions may not be as much (unnecessary) “overkill” as you might first think.

In the general case, to provide an inviolate status line on some given terminal, you will need a full terminal (re)emulator that sits between the original terminal and a new terminal (one with one fewer lines). Such (re)emulation is needed to translate control sequences sent to the inner terminal and translate them for the original terminal. For example, to maintain a status line at the bottom of the outer terminal, the command

Move to the last line.

sent to the inner terminal must be become

Move to the next to last line.

when translated for and sent to the outer terminal. Likewise, an LF sent to the inner terminal must become

If the cursor is on the next to last line, then scroll this line and all the lines above it up one line, to provide a clear next-to-last line (protecting the status line on the last line). Otherwise, send an LF.

in the outer terminal.

Programs like tmux and screen are just such terminal re-emulators. Sure, there is a lot of other functionality wrapped around the terminal emulator, but you would need a large chunk of terminal emulation code just to provide a reliable status line.


There is, however, a light-weight solution as long as

  1. your programs (Node.js instances) have limited terminal interactions with the panes in which they are running (i.e. no cursor positioning), and
  2. you do not resize the panes while your programs are running.

Like many terminal emulators, tmux supports a “set scrolling region” terminal control command in its panes. You could use this command to limit the scrolling region to the top (or bottom) N-1 lines of the terminal and write some sort of instance-identifying text into the non-scrolling line.

The restrictions (no cursor movement commands allowed, no resizing) are required because the program that is generating the output (e.g. a Node.js instance) has no idea that scrolling has been limited to a particular region. If the output-generating program happened to move the cursor outside of the scrolling region, then the output might become garbled. Likewise, the terminal emulator probably automatically resets the scrolling region when the terminal is resized (so the “non-scrolling line” will probably end up scrolling away).

I wrote a script that uses tput to generate the appropriate control sequences, write into the non-scrolling line, and run a program after moving the cursor into the scrolling region:

#!/bin/sh

# usage: no_scroll_line top|bottom 'non-scrolling line content' command to run with args
#
#     Set up a non-scrolling line at the top (or the bottom) of the
#     terminal, write the given text into it, then (in the scrolling
#     region) run the given command with its arguments. When the
#     command has finished, pause with a prompt and reset the
#     scrolling region.

get_size() {
    set -- $(stty size)
    LINES=$1
    COLUMNS=$2
}
set_nonscrolling_line() {
    get_size
    case "$1" in
        t|to|top)
            non_scroll_line=0
            first_scrolling_line=1
            scroll_region="1 $(($LINES - 1))"
            ;;
        b|bo|bot|bott|botto|bottom)
            first_scrolling_line=0
            scroll_region="0 $(($LINES - 2))"
            non_scroll_line="$(($LINES - 1))"
            ;;
        *)
            echo 'error: first argument must be "top" or "bottom"'
            exit 1
            ;;
    esac
    clear
    tput csr $scroll_region
    tput cup "$non_scroll_line" 0
    printf %s "$2"
    tput cup "$first_scrolling_line" 0
}
reset_scrolling() {
    get_size
    clear
    tput csr 0 $(($LINES - 1))
}

# Set up the scrolling region and write into the non-scrolling line
set_nonscrolling_line "$1" "$2"
shift 2

# Run something that writes into the scolling region
"$@"
ec=$?

# Reset the scrolling region
printf %s 'Press ENTER to reset scrolling (will clear screen)'
read a_line
reset_scrolling

exit "$ec"

You might use it like this:

tmux split-window '/path/to/no_scroll_line bottom "Node instance foo" node foo.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance bar" node bar.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance quux" node quux.js'

The script should also work outside of tmux as long as the terminal supports and publishes its csr and cup terminfo capabilities.

Beecham answered 18/3, 2012 at 9:0 Comment(6)
your script works exactly as I expected; the only question: what should I google to customize the color of the "non_scroll_line"?Spaceless
Maybe “terminfo capability foreground background color” (i.e. read about color in terminfo manpage). You can use tput to include the appropriate control sequences in the “line content” argument. With most terminals, you could make the line be “cyan (6) and green (3) on magenta (5)” with no_scroll_line top "$(tput setaf 6; tput setab 5)Node: $(tput setaf 3)foo$(tput op)" node foo.js. setaf sets the foreground, setab sets the background, op resets to the terminals default colors. The color capabilities take a number from 0–7, 0–15, 0–87, or 0–255, depending on your terminal emulation.Beecham
We now released pymux. This displays pane title bars:github.com/jonathanslenders/pymuxBlown
It seems that the behavior is that the pane title is set to the command being run in the shell. So it won't "stick" unless we're running one long-lived process (which also knows how to output the title-setting escape sequence) inside.Directive
What I'm looking to do is assign a name to a pane to reference it programmatically and send it keystrokes without manually switching to it. Seems like I can work around this for now using the mark feature.Directive
Please take a look at the answer further below: https://mcmap.net/q/167274/-pane-title-in-tmux tmux as of version 2.3 supports titles in pane borders.Mainland
C
124

This functionality has been added to tmux in this commit. It is not in version 2.2, but it looks like it will be in 2.3.

To enable it:

tmux set -g pane-border-status top

or if you prefer:

tmux set -g pane-border-status bottom

To set a custom text as your pane border status line you can make use of pane-border-format, e.g. like so:

tmux set -g pane-border-format "#{pane_index} #{pane_current_command}"
Commissioner answered 2/6, 2016 at 21:2 Comment(6)
This shows the number of the pane and a default title. How do you change it thought?Noble
I'm not sure about the pane numbers, but it responds like an xterm window title to escape sequences. For example, with bash, I have set PS1='[\e]0;\u@\h: \w\a]$ ' to get "user@host: working dir/"Commissioner
As far as I understand, you set that sequence before hand. But there is no shortcut or key combination that changes them. So, in tmux you need some command outside tmux to change it. Right? Or is there any sequence inside that can update it?Noble
Yeah, you just set the variable in the running shell and it updates when the next prompt is drawn. For me it seems that tmux is a little sketchy and only actually updates it when you switch to another pane.Commissioner
You can actually use pane-border-format to set a custom format string for the pane to display (the usual #{...} format). I have edited your answer to include this.Mainland
@Noble just replace pane_current_command with pane_current_pathChevrotain
B
96

tmux does support per-pane titles, but it does not provide a per-pane location to display these titles.

You can set a pane’s title with the escape sequence ESC ]2; … ESC \ (e.g. see the section called Names and Titles in the tmux manpage). You could do this from the shell like this:

printf '\033]2;%s\033\\' 'title goes here'

Each pane’s title defaults to the system’s hostname. By default the active pane’s title is displayed on the right side of the tmux status line (the default global value of the session variable status-right is "#22T" %H:%M %d-%b-%y, which shows 22 characters of the pane’s title, the time, and the date).

So, as long as you are satisfied with being able to see the active pane’s title (i.e. willing to switch panes to see the title of an inactive pane), you can get by with the default functionality. Just send the appropriate title-setting escape sequence before starting the main command for each pane.


If you absolutely need a dedicated line to display some per-pane information, then nested tmux sessions may not be as much (unnecessary) “overkill” as you might first think.

In the general case, to provide an inviolate status line on some given terminal, you will need a full terminal (re)emulator that sits between the original terminal and a new terminal (one with one fewer lines). Such (re)emulation is needed to translate control sequences sent to the inner terminal and translate them for the original terminal. For example, to maintain a status line at the bottom of the outer terminal, the command

Move to the last line.

sent to the inner terminal must be become

Move to the next to last line.

when translated for and sent to the outer terminal. Likewise, an LF sent to the inner terminal must become

If the cursor is on the next to last line, then scroll this line and all the lines above it up one line, to provide a clear next-to-last line (protecting the status line on the last line). Otherwise, send an LF.

in the outer terminal.

Programs like tmux and screen are just such terminal re-emulators. Sure, there is a lot of other functionality wrapped around the terminal emulator, but you would need a large chunk of terminal emulation code just to provide a reliable status line.


There is, however, a light-weight solution as long as

  1. your programs (Node.js instances) have limited terminal interactions with the panes in which they are running (i.e. no cursor positioning), and
  2. you do not resize the panes while your programs are running.

Like many terminal emulators, tmux supports a “set scrolling region” terminal control command in its panes. You could use this command to limit the scrolling region to the top (or bottom) N-1 lines of the terminal and write some sort of instance-identifying text into the non-scrolling line.

The restrictions (no cursor movement commands allowed, no resizing) are required because the program that is generating the output (e.g. a Node.js instance) has no idea that scrolling has been limited to a particular region. If the output-generating program happened to move the cursor outside of the scrolling region, then the output might become garbled. Likewise, the terminal emulator probably automatically resets the scrolling region when the terminal is resized (so the “non-scrolling line” will probably end up scrolling away).

I wrote a script that uses tput to generate the appropriate control sequences, write into the non-scrolling line, and run a program after moving the cursor into the scrolling region:

#!/bin/sh

# usage: no_scroll_line top|bottom 'non-scrolling line content' command to run with args
#
#     Set up a non-scrolling line at the top (or the bottom) of the
#     terminal, write the given text into it, then (in the scrolling
#     region) run the given command with its arguments. When the
#     command has finished, pause with a prompt and reset the
#     scrolling region.

get_size() {
    set -- $(stty size)
    LINES=$1
    COLUMNS=$2
}
set_nonscrolling_line() {
    get_size
    case "$1" in
        t|to|top)
            non_scroll_line=0
            first_scrolling_line=1
            scroll_region="1 $(($LINES - 1))"
            ;;
        b|bo|bot|bott|botto|bottom)
            first_scrolling_line=0
            scroll_region="0 $(($LINES - 2))"
            non_scroll_line="$(($LINES - 1))"
            ;;
        *)
            echo 'error: first argument must be "top" or "bottom"'
            exit 1
            ;;
    esac
    clear
    tput csr $scroll_region
    tput cup "$non_scroll_line" 0
    printf %s "$2"
    tput cup "$first_scrolling_line" 0
}
reset_scrolling() {
    get_size
    clear
    tput csr 0 $(($LINES - 1))
}

# Set up the scrolling region and write into the non-scrolling line
set_nonscrolling_line "$1" "$2"
shift 2

# Run something that writes into the scolling region
"$@"
ec=$?

# Reset the scrolling region
printf %s 'Press ENTER to reset scrolling (will clear screen)'
read a_line
reset_scrolling

exit "$ec"

You might use it like this:

tmux split-window '/path/to/no_scroll_line bottom "Node instance foo" node foo.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance bar" node bar.js'
tmux split-window '/path/to/no_scroll_line bottom "Node instance quux" node quux.js'

The script should also work outside of tmux as long as the terminal supports and publishes its csr and cup terminfo capabilities.

Beecham answered 18/3, 2012 at 9:0 Comment(6)
your script works exactly as I expected; the only question: what should I google to customize the color of the "non_scroll_line"?Spaceless
Maybe “terminfo capability foreground background color” (i.e. read about color in terminfo manpage). You can use tput to include the appropriate control sequences in the “line content” argument. With most terminals, you could make the line be “cyan (6) and green (3) on magenta (5)” with no_scroll_line top "$(tput setaf 6; tput setab 5)Node: $(tput setaf 3)foo$(tput op)" node foo.js. setaf sets the foreground, setab sets the background, op resets to the terminals default colors. The color capabilities take a number from 0–7, 0–15, 0–87, or 0–255, depending on your terminal emulation.Beecham
We now released pymux. This displays pane title bars:github.com/jonathanslenders/pymuxBlown
It seems that the behavior is that the pane title is set to the command being run in the shell. So it won't "stick" unless we're running one long-lived process (which also knows how to output the title-setting escape sequence) inside.Directive
What I'm looking to do is assign a name to a pane to reference it programmatically and send it keystrokes without manually switching to it. Seems like I can work around this for now using the mark feature.Directive
Please take a look at the answer further below: https://mcmap.net/q/167274/-pane-title-in-tmux tmux as of version 2.3 supports titles in pane borders.Mainland
B
80

Since tmux 2.6 you can do:

$ tmux select-pane -t {pane} -T {title}

# Examples:
$ tmux select-pane -T title1          # Change title of current pane
$ tmux select-pane -t 1 -T title2     # Change title of pane 1 in current window
$ tmux select-pane -t 2.1 -T title3   # Change title of pane 1 in window 2

You can see title per pane in a status bar with:

$ tmux set pane-border-status bottom      # For current window
$ tmux set -g pane-border-status bottom   # For all windows

Disable status bar with:

$ tmux set pane-border-status off       # For current window
$ tmux set -g pane-border-status off    # For all windows
Brachyuran answered 25/4, 2019 at 9:25 Comment(4)
Do you know if there's any way to prevent tmux from changing the title out from under you? For example, if I set a pane's title and then do something in that pane, like cd $HOME, the title is changed to the value of $HOME. (I'm seeing this on tmux 2.8.)Kleon
@Kleon Maybe you already got the answer, but check out set-window-option automatic-rename off.Lyndseylyndsie
I have set-option -g allow-rename off in my .tmux.conf file.Brachyuran
Thanks for the suggestions. I wound up using pane-border-format and a user provided variable (I'm not sure if there's an official name for this feature) to control what's displayed. Here's an example.Kleon
D
20

I am using tmux version 2.3, I think border style is not supported in previous versions. this is what worked for me:

For each pane set the title:

printf '\033]2;My Pane Title\033\\'

Then:

tmux set -g pane-border-format "#{pane_index} #T"
Degression answered 24/1, 2017 at 3:33 Comment(3)
At least as recent as tmux 2.6, you can change the pane title within tmux: select-pane -T "my title" does this. You can even set up a key binding so you just need to supply the title: bind-key T command-prompt -p "New title:" 'select-pane -T "%%"'Myo
@Myo maybe i haven't followed this thread, but this seems like the answer.Tani
@Myo I'm not 100% sure but I believe your method (which IMO is the best and simplest in this entire thread, for recent versions of tmux) only works if the pane-border-status option is set to something (top or bottom).Pisciculture
I
19

A gif is worth a thousand words. (source)

tmux-xpanes is a tmux-based terminal divider, which supports displaying title for each pane through the newly added -t option.

Inhalation answered 6/7, 2018 at 2:49 Comment(2)
A gif is worth a thousand words, but if it ever link rots it's worth none.Unblushing
TBH the gif is more confusing than helpful. Cluttered and too fast so that the intention is absolutely not clear. Only after making 2 screenshots, one after the first command, another one after the second, modified command, I understood what's going on. Not downvoting it because of the effort you have put into it, and at that time it may have been the best solution (if it was pre v2.6)Simdars
B
15

I'm working on the pane status bar for tmux - ticket. My development branch can be found here on github: https://github.com/jonathanslenders/tmux

Right now, this already adds a working rename-pane "title" command. There are still some bugs, and the API will improve. The idea is to create a status bar per pane, which can have some formatting, like the session status bar. Like the rest of tmux, everything should become scriptable, and customizable. When finished and stable, it will probably be included in the official tmux.

Blown answered 12/4, 2013 at 10:1 Comment(3)
While you're in there, can you make it so that the pane title becomes the default window title during a break-pane?Seafood
This branch was never merged in tmux. But I created pymux instead, which has pane title bars: github.com/jonathanslenders/pymuxBlown
This command doesn't work on latest build either (commit a24260).Noble
P
8

Adding these three lines inside .tmux.conf worked and doesn't intervene with the pane_title variable managed by tmux

set -g pane-border-status top
set -g pane-border-format "#[fg=black, bg=green] #{pane_index} #{@custom_pane_title}"
bind < command-prompt -p "New Title: " -I "#{@custom_pane_title}" "set-option -p @custom_pane_title '%%'"

After adding these lines, source the .tmux.conf to reflect the changes

tmux source-file ~/.tmux.conf

Inside tmux pane, press Ctrl+B <, enter the title of your choice, and pane title will be set.

The rationale to use a different variable

Pane title can be set from multiple sources, and I wanted to avoid any interference with it.

  1. tmux select-pane -T title1
  2. using escape sequence characters `printf '\033]2;%s\033\' 'title goes here

ref: https://gist.github.com/ethagnawl/db27bba3c4cccdc30ade2a0c54f49723

Pompeii answered 20/7, 2022 at 11:18 Comment(2)
This worked wonders. It is also immune to pan layout changes. Thanks for this. Logged in specifically to upvote this.Gladsome
Only solution I found with which the title is not overridenPrier
V
7

Yes there is such a command: tmux. Give your session a name and it will be displayed in an inner status bar:

TMUX=0 tmux new-session -s my-new-session
Vinita answered 17/3, 2012 at 16:41 Comment(3)
Yes, thank you for your answer! But thus I'll have to launch a new tmux session in every pane just for one title in the bottom of it - kind of overkill, isn't it?Spaceless
I don't know. Is it? Have you tried it? How much extra memory is the extra session using?Vinita
yeah, I've been using nested tmux sessions until today. I'm not sure about memory consumption and things like this - I just dislike the concept itself 'cause its not pure.Spaceless
C
5

TL;DR

Append following configs to your tmux config file (in my case is ~/.tmux.conf.local)

# display pane_current_path as the pane title
set -g pane-border-status top
set -g pane-border-format "#{pane_index} #{pane_current_path}"

then run:

tmux source-file ~/.tmux.con

enjoy it

Thanks to https://mcmap.net/q/167274/-pane-title-in-tmux

Chevrotain answered 27/7, 2020 at 7:53 Comment(0)
J
4

This is not helpful in the short-term, but there is a feature request for per-pane titles in tmux: http://sourceforge.net/tracker/?func=detail&aid=3495916&group_id=200378&atid=973265#

In the meantime, as others mentioned, nesting tmux works decently.

Johnathanjohnathon answered 19/10, 2012 at 21:5 Comment(0)
D
1

All existing answers don't mention how to actually change the default title, but the solution is hidden over at https://unix.stackexchange.com/a/564690/28354, and, for example, on Android Termux tmux, you can change the default title of "localhost" to the model name instead, like so, from within a zsh shell:

tmux set-hook -g after-split-window "select-pane -T \"$(getprop ro.product.model)\""
tmux set-hook -g after-new-window "select-pane -T \"$(getprop ro.product.model)\""
tmux set-hook -g after-new-session "select-pane -T \"$(getprop ro.product.model)\""

This will change the "localhost" from bottom-right status bar next to the clock, because pane_title is what's used, which, in turn, defaults to the hostname:

% tmux show-options -g status-right
status-right "#{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,}\"#{=21:pane_title}\" %H:%M %d-%b-%y"
[0] 0:zsh  1:zsh  2:zsh- 3:zsh*                         "Pixel 2 XL" 22:55 26-Sep-21

Additionally, it can be made to be displayed at the top of each pane, too:

tmux set -g pane-border-status top

The format is controlled by pane-border-format, and it defaults as follows:

% tmux show-options -g pane-border-format
pane-border-format "#{?pane_active,#[reverse],}#{pane_index}#[default] \"#{pane_title}\""
Doloresdolorimetry answered 27/9, 2021 at 4:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.