Pane Title in Tmux - command-line

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?

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}"

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
your programs (Node.js instances) have limited terminal interactions with the panes in which they are running (i.e. no cursor positioning), and
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.

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

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"

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.

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.

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

TL;DR
Append following configs to your tmux config file (in my case is ~/.tmux.conf.local)
# dispaly 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://stackoverflow.com/a/37602055/5121972

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.

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.
tmux select-pane -T title1
using escape sequence characters `printf '\033]2;%s\033\' 'title goes here
ref: https://gist.github.com/ethagnawl/db27bba3c4cccdc30ade2a0c54f49723

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}\""

Related

Configure binding to perform predefined search in Tmux

I'm trying to find a way to jump to the previous prompt in iTerm using tmux. Can I set a binding to search a unique phrase within my prompt?
So to expand on Yuriy's answer. Inside your terminal you can run the following commands:
tmux copy-mode ; tmux send -X search-backward 'Example'
That should put your current tmux pane into copy-mode and then initiate a search for 'Example'. Now instead of typing that every time we want to search we'll create a shell script(lets say /tmp/search.sh) and then a tmux binding to that script
Contents of /tmp/search.sh
#!/usr/bin/env bash
tmux copy-mode ; tmux send -X search-backward 'These'
make sure you make it executable with chmod +x /tmp/search.sh. At this point you can test that it works by simply calling the script from your tmux session. To add it as a binding you can something akin to the following to your ~/.tmux.conf file:
bind p run-shell "bash /tmp/search.sh"
Make sure you source refresh the configuration in your tmux session and your new binding should initiate the search.
The canonical way of doing this is write a bash script to issue the commands back to your tmux.
But I'd like to suggest a mod that allows way more flexible scripting: http://ershov.github.io/tmux/ (I'm the author)
Using this mod, your problem can be solved this way:
bind p copy-mode ";" tcl {
set s [copy-mode-screenline -ex [copy-mode-get-cx]]
cursor-up
send-keys "?" "\x15$s"
}
This will read the current line from the beginning up to the cursor position and search for the previous occurrence of it.
The key 'p' can be changed to your preference.

Set size of a cygwin terminal window

I have a small perl script, which is executed in a cygwin terminal and prints out a formatted table.
On Default window size, cygwin will insert an line break if the text gets too long and thereby destroy the format of my table.
Is there a way from my perl script to set the cygwin window to a bigger size to avoid that kind of problem?
If you happen to be running this from a shortcut where you could add flags to the mintty command, you can set the size then. The benefit is that it looks smoother without the twitchy resize.
$ /cygdrive/c/tools/cygwin/bin/mintty.exe --help
Usage: mintty [OPTION]... [ PROGRAM [ARG]... | - ]
Start a new terminal session running the specified program or the user's shell.
If a dash is given instead of a program, invoke the shell as a login shell.
Options:
-c, --config FILE Load specified config file (cf. -C or -o ThemeFile)
-e, --exec ... Treat remaining arguments as the command to execute
-h, --hold never|start|error|always Keep window open after command finishes
-p, --position X,Y Open window at specified coordinates
-p, --position center|left|right|top|bottom Open window at special position
-p, --position #N Open window on monitor N
-s, --size COLS,ROWS Set screen size in characters (also COLSxROWS)
-s, --size maxwidth|maxheight Set max screen size in given dimension
-t, --title TITLE Set window title (default: the invoked command) (cf. -T)
-w, --window normal|min|max|full|hide Set initial window state
-i, --icon FILE[,IX] Load window icon from file, optionally with index
-l, --log FILE|- Log output to file or stdout
--nobidi|--nortl Disable bidi (right-to-left support)
-o, --option OPT=VAL Set/Override config file option with given value
-B, --Border frame|void Use thin/no window border
-R, --Reportpos s|o Report window position (short/long) after exit
--nopin Make this instance not pinnable to taskbar
-D, --daemon Start new instance with Windows shortcut key
-H, --help Display help and exit
-V, --version Print version information and exit
See manual page for further command line options and configuration.
If you are using mintty as your terminal emulator (it has been the default
terminal emulator for Cygwin for the past couple of years), you can use ANSI
escape codes to manipulate the terminal.
You can test this by running the following snippet of Perl code to change the size of your terminal emulator window:
# If terminal supports ANSI escape sequences
$lines = 80;
$columns = 100;
print "\e[8;$lines;${columns}t";
Note: This doesn't work if run while in a screen window and I don't know why. According to the screen man page, this escape sequence should be supported.
Explanation
The syntax of ANSI escape sequences isn’t the easiest to read but here’s the
documentation that provides the basis of the above sequence.
The \e prints an Escape character which begins the ANSI escape sequence.
This is also known as the Control Sequence Introducer (CSI).
The specific sequence ending with t comes from this List of xterm control
sequences
CSI Ps ; Ps ; Ps t
Window manipulation (from dtterm, as well as extensions).
These controls may be disabled using the allowWindowOps
resource. Valid values for the first (and any additional
parameters) are:
…
Ps = 8 ; height ; width -> Resize the text area to given
height and width in characters. Omitted parameters reuse the
current height or width. Zero parameters use the display's
height or width.
You don't even need Perl, you can do the same in Bash:
echo -en "\e[8;35;100t";
Or why not a script:
#!/bin/bash
# minsize - A TTY re-size escape sequence for use with mintty Cygwin
# Usage: minsize <width> <height>
WIDTH=$1
HEIGHT=$2
echo -en "\e[8;${HEIGHT};${WIDTH}t";
Note, that on other *nixes there is ttysize available.

Using Emacs as a server and opening only one window exactly, which should be maximized

I'd like to run my Emacs in daemon mode, and then use emacsclient to actually display things. However, if I run emacsclient filename, it shows up in the terminal, which isn't what I want; I instead have to pass it the -c option.
However, that option always creates a new frame, which isn't what I want - I'd rather just have one frame, and have stuff open in a new buffer in the same frame if it already exists; otherwise, it should make me a new frame. However, I'm not sure how to do this.
Additionally, I want that one frame to be maximized, which I usually achieve my starting Emacs with the -mm option; how would I ensure that a frame made by emacsclient is also maximized?
The following script does the following:
start Emacs server if necessary
if there are no open frames, open a new one
open the given file(s) in the current frame
#!/bin/bash
# Selected options for "emacsclient"
#
# -c Create a new frame instead of trying to use the current
# Emacs frame.
#
# -e Evaluate the FILE arguments as ELisp expressions.
#
# -n Don't wait for the server to return.
#
# -t Open a new Emacs frame on the current terminal.
#
# Note that the "-t" and "-n" options are contradictory: "-t" says to
# take control of the current text terminal to create a new client frame,
# while "-n" says not to take control of the text terminal. If you
# supply both options, Emacs visits the specified files(s) in an existing
# frame rather than a new client frame, negating the effect of "-t".
# check whether an Emacs server is already running
pgrep -l "^emacs$" > /dev/null
# otherwise, start Emacs server daemon
if [ $? -ne 0 ]; then
emacs --daemon
fi
# return a list of all frames on $DISPLAY
emacsclient -e "(frames-on-display-list \"$DISPLAY\")" &>/dev/null
# open frames detected, so open files in current frame
if [ $? -eq 0 ]; then
emacsclient -n -t "$#"
# no open frames detected, so open new frame
else
emacsclient -n -c "$#"
fi
Edit: fixed expansion of positional arguments (2017-12-31).
For having every new frame maximized, you could add this to your .emacs:
(modify-all-frames-parameters '((fullscreen . maximized))))
Is your DISPLAY env set in the terminal where you're running emacsclient? Because the behavior you request should be the default (the behavior of reusing existing frames, I mean).

How can I modify command line in Ubuntu 10.04?

I am using a vpn service from certain server. I was given with a root account, and when I connect with a root account, the command line looks like below.
root#xa9g82:/etc/#
Then I used useradd to add an account called 'temp'
When I connected to the server with temp, then the command line only has a single character.
$
The user information is not shown, neither the path. Also, note that, in root's command line I can use tab to automatically complete the filename, however 'temp's command line inserts tab space, when I press tab. It is very inconvenient.
I am using Ubuntu 10.04. How can I resolve this issue?
I usually edit ~/.bashrc. Being root, you might want to change the system-wide preferences, at /etc/bash.bashrc. Personally, I changed some lines in ~/.bashrc to look like:-
# If this is an xterm set the title to user#host:dir
case "$TERM" in
xterm*|rxvt*)
## PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u#\h: \w\a\]$PS1" # default
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\h: \W\a\]$PS1" # How I like it
;;
*)
;;
esac
use prompt to set the prompt.... (man prompt...)
it depends on what shell you run each one has it's own tricks, but you can make it looks as you wish.
BASH
TCSH
It is likely that the default shell for root is set to /bin/sh, which does not provide many of the features that you may used to if you use a shell like bash. To check if this is the case, run the following command:
cat /etc/passwd | grep ^root
The last component of the line that this command outputs will be your shell (which, as stated previously, I'm guessing is /bin/sh). If this is not the shell you want (it probably isn't), then edit /etc/passwd (using nano or whatever editor you're most comfortable with) and change your shell to something more palatable, like /bin/bash. After doing this, you'll need to log out and then log back in.

emacsclient window focus

How do I consistently control window focus after running emacsclient?
Currently, focus depends on if I already have an emacs server running. When emacsclient invokes an alternative editor, focus is shifted to the new emacs window. When emacsclient connects to an existing emacs server, focus is not shifted (ie. it stays on my putty client).
I would like to consistently focus on the emacs window, since I usually go to emacs after opening a file.
Any help would be greatly appreciated!
Notes
Version Info
emacs: 21.4.1
emacsclient: 21.4
client os: Windows XP Service Pack 3
x server: Exceed 11.0.0.0
Relevant section of my .bash_profile
# a wrapper is needed to sandwich multiple command line arguments in bash
# 2>/dev/null hides
# "emacsclient: can't find socket; have you started the server?"
emacs_wrapper () {
if [ 0 -eq $# ]
then
emacsclient -n -a emacs ~/notes.txt 2>/dev/null &
else
emacsclient -n -a emacs $* &
fi
}
alias x="emacs_wrapper"
Also, at the end of my .emacs I have
(server-start)
My current workaround is a simple autohotkey script, which focuses on my first Exceed window
^+x::
If WinExist("ahk_class EXCEEDW:MWCLIENT0")
WinActivate
return
As a side note, it seems my redirection to /dev/null confused the syntax-highlighter :(
How about:
emacsclient -e "(select-frame-set-input-focus (selected-frame))"
works for me on emacs 23.1
To unfocus (lower-frame) might be useful.
Would the "--create-frame" option to emacsclient work for you? You'd get a new frame for each file you opened this way, but at least it would be focused (I think).
For some unknown reason, the issue fixed itself. Opening files now consistently changes focus to the emacs frame with the corresponding file. I'm honestly unsure what changed the behavior, but I'm happy.
Thanks to everyone for their comments and suggestions!