tmux only shows current pane title if queried from a key binding - tmux

Suppose have 3 panes in a tmux window: vim, vom, and vam
I want to access the pane title of the first pane as part of a keyboard mapping (forward command to vim if vim's in pane 1). It wasn't working as expected and I've narrowed it down to the following...
If I run:
tmux display-message "`tmux list-panes -F '#{pane_title}'`"
the result is:
vim
vom
vam
This is what I'd expect. If I try to run the same from a key mapping:
bind -n C-h run "tmux display-message \"`tmux list-panes -F '#{pane_title}'`\""
I get the title of the current pane repeated three times:
vom
vom
vom
Does run-shell execute in a different context or something?
Thanks for your help

Run tmux list-keys in the terminal and see what C-h gets mapped to. I get something like this:
bind-key C-t run-shell "tmux display-message "name1
name2
name3""
From the above, you can see the backtick interpolation happens at the moment when the key is bound, not later when the binding is executed.
I don't know how to get around this and you must be having a lot of pain because of so many nested commands.
Personally, when hacking tmux I always apply the rule of "get to the shell as soon as possible".
For your example that would mean:
keep the key binding simple: bind -n C-h run "/path/to/script.sh"
create a script, make it executable and put the rest of what you want to do in it. This would be its content:
tmux display-message "`tmux list-panes -F '#{pane_title}'\`"
I just did it and it worked for me locally. Hope that helps!

Related

tmux: allow-rename, but ALSO override?

I'd like to be able to issue a command like this:
tmux new-window -n irc ssh -t eco /usr/bin/weechat
and have the title of the new window be "irc". Instead, as soon as weechat launches, the title changes to weechat.
I had been under the impression based on the tmux man page that if you set a window title explicitly, automatic-rename would be disabled for you:
automatic-rename
[...] This flag is automatically disabled for an individual window when a
name is specified at creation with new-window or new-session, or later
with rename-window, or with a terminal escape sequence.
But that seems to not be the case. What am I missing here? I do want automatic-rename in most cases - I just want to also be able to specify -n windowname and have it take precedence.

tmux split-window without changing focus

Is there any way to split a window in tmux without changing the current focus?
I'm running a script inside one of my tmux panes that occasionally runs "tmux split-window ..." with some command that takes a minute to complete and MAY request input.
I can end up trying to type input into one of the tmux panes but in the middle of my typing, the original pane executes "tmux split-window ..." and (mid word) my cursor shifts to the new pane, and I end up typing part of the input into the wrong pane.
Note: this answer is correct, but obsolete. The right way is to use -d flag for split-window command. I'm leaving this answer as a demonstration how to do some yak shaving with tmux.
A split-window command flag provided by tmux would be the right solution for this. Unfortunately tmux does not provide such command flag. Update: there is a -d split-window flag that does this.
The simple solution is to immediately switch to previous pane after split-window:
tmux split-window
tmux last-pane
This can be also written as a one liner:
tmux split-window\; last-pane
The downside of this solution is that *theoretically* you might end up writing a character in the wrong window if you type it in time interval between split-window and last-pane command execution.
Here another approach with the downside that it's more complex.
Create a new window in the background and get the pane_id of this window (note how this command is wrapped in $(...) because we want it executed in a subprocess:
pane_id=$(tmux new-window -d -P -F "#{pane_id}")
Now join the window we just created with the window where your cursor is located (will not change cursor focus):
tmux join-pane -b -t "$pane_id"
Add -h to the join-pane above if you want a horizontal split.
I recommend taking the first approach for it's simplicity. It's highly unlikely you'll have any practical issues with it.

tmux resize on focus

I'd like to be able to specify a secondary size parameter for a particular pane so that it assigns the new size upon focusing the pane, and returns it upon exiting. So e.g.
(Note [] represents focused terminal cursor)
________________
|$ ls | |
|a's | |
|dir | |
|$ |$ [] |
|______|_______|
Swap pane focus
_______________
| | |
|$ ls | |
|a's dir | |
|$ [] |$ |
|________|____|
And so on. Especially gonna be cool since resizing panes in recent tmux versions has it do a great job re-flowing the content rather than slicing it off.
In the example, the left pane has its width set to automatically switch to being 8 columns when it is focused, and it got squished thinner when it lost focus. Notice how the content is still visible (this is afterall why we love tmux) but we can still eat our cake too by letting the currently focused pane expand itself automatically so it's always big enough to do work in!
I can probably come up with some elaborate binds to automate the application of resize-pane commands to do this, and make it just the right amount of elaborate to suit my wishes. But I was hoping there was some kind of built-in feature for this.
It would be practical to track and allow the modification of an auxiliary 4-tuple of integers for each pane. These specify the amount of resize-pane -L/D/U/R operations to do upon that pane's focusing, and the reverse direction upon that pane's defocusing.
There may be other, more reasonable formulations of this.
Found a partial solution...
Ive got my pane switching synced with vim, so whenever I switch switch panes, I also resize tmux.
This is not optimal because tmux is not verifying the current pane size and resizing it accordingly. Anyway, it works pretty well since you can do ctr-h or ctrl-k twice to resize the panes size.
The relevant config is the following:
# Sync panes with vi
bind -n C-h run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)vim(diff)?$' && tmux send-keys C-h) || tmux select-pane -L && tmux resize-pane -R 30"
bind -n C-l run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)vim(diff)?$' && tmux send-keys C-l) || tmux select-pane -R && tmux resize-pane -L 30"
bind -n C-j run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)vim(diff)?$' && tmux send-keys C-j) || tmux select-pane -D"
# Move panes up and down, wont resize
bind -n C-k run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)vim(diff)?$' && tmux send-keys C-k) || tmux select-pane -U"
Sorry, this only amounts to speculation so far, but I thought about it some, and I think there is functionality that is built in to tmux that can support this but it'll require some/a lot of scripting.
See this question I posted.
http://sourceforge.net/p/tmux/mailman/message/31221459/
Essentially it looks like the select-layout command can (possibly!??!) be used to apply an arbitrary mutation to the layout. I've not tested if it works, though.
Thomas Adam suggested to look in the layout-custom.c source to find out more about what's going on. That's about as far as I got. But if indeed it is possible to programmatically mutate the layout and generate working strings to pass to select-layout, then this would be a very good approach.
Update: Now I have asked this directly (whether just generating a suitable string can indeed achieve resizing to arbitrary layouts), but not yet received a response, from Mr. Adam himself, but the reason why I suspect that this can work if we can generate a string that passes the checksum is that I am able to resize my panes any which way, and change them away once I record the string (yielded by the list-windows command), and then afterwards restore to the recorded layout with the string. This means that there is not some sort of explicit action that must be taken to like "save" the layout or anything, it seems like the checksum is just some kind of clever way to help prevent garbage/pathological strings from wreaking havoc with the string interpreter that does the pane layout rearrangement.
You definitely need to pass a string that is nontrivial to construct in order for this to work. However, the code for computing the checksum and the rest is plain to see in layout-custom.c. One day I'll probably be back with a shell script (or just a C program, if it's possible to lift out the code) that implements suitable transformations. Should be fun.
Yes it would be awesome for me to crank this out and pick up that nice little bounty, but I have Real WorkTM waiting for me tonight unfortunately.

Split pane switching in tmux: switch once per command

I've been a happy tmux user for a while now but there's one behaviour that's bugging me. When I switch panes using ^b-arrow, and then immediately press arrow-up (to get a command from history, for example), the window pane switches again. I understand this can be useful if you want to move through multiple panes quickly, but for me it's a pain in the backside since I keep ending up in panes I never meant to be in.
So, is there a way to set tmux so that the ^b-arrow command only switches pane once and ignores any following arrow key presses?
That happens because the default bindings for the arrow keys are setup with bind-key -r, specifying that they may be repeated. There are two ways that you can disable this.
First, you can use set-option repeat-time 0 to disable repeating entirely. This will affect all bindings. I find that to be very annoying when resizing panes.
Secondly, you can change the bindings for the arrow keys to use bind-key without the -r option:
bind-key Up select-pane -U
bind-key Down select-pane -D
bind-key Left select-pane -L
bind-key Right select-pane -R
If you spend a lot of times navigating panes, why not set up global mappings so you don't have to use prefixes at all, e.g. bind -n C-h select-pane -L to map ctrl-h to switching left, same as Vim.
See http://robots.thoughtbot.com/seamlessly-navigate-vim-and-tmux-splits for an even better solution that also navigates across Vim windows.
Another option is to make a binding to jump to the previous pane, if you are flicking back and forth between the same two panes.
bind-key C-a last-pane

tmux maximize/minimize pane bug -- "Session not found: tmp"

description of what's happening:
when minimizing a maximized pane, this message appears at bottom of terminal window: "Session not found: tmp"
pane appears to return to same place as initial/previous session
but the new tmp window (that was opened when the pane was first maximized) fails to close and appears in the list of windows (in the status bar at the bottom of tmux)
my hunch is kill-window -t tmp (in the below .tmux.conf code) is where things break. since executing a command in the tmp window appears to rename the window, kill-window -t tmp won't work.
so my question is: how could i alter .tmux.conf to prevent this from happening?
steps to recreate bug:
(note: you would need to have modified .tmux.conf for these commands to work)
start tmux and create session w/ at least two panes
maximize one pane using [prefix] + [up]
execute a shell command in maximized pane (*)
minimize pane using [prefix] + [down]
(*) if pane is maximized and minimized w/out executing a command in the shell this problem does not appear to occur. i.e. if you're editing a file in a pane, then maximize that pane, and only edit/save the file (w/out exiting and then executing another command), then minimize -- the bug doesn't occur.
30s youtube clip showing what happens: http://youtu.be/WMdOeJdOYuU
code that might be causing the error (from ~/.tmux.conf):
unbind Up
bind Up new-window -d -n tmp \; swap-pane -s tmp.0 \; select-window -t tmp
unbind Down
bind Down last-window \; swap-pane -s tmp.0 \; kill-window -t tmp
[edit: HERE IS THE SOLUTION]
thanks to a helpful #tmux irc'er (who has this link and whom i will happily give credit) this question is solved. i don't yet have enough cred to answer this question so i'm posting the solution here.
the solution is to add set-window-option -g allow-rename off to ~/.tmux.conf
this works b/c tmp doesn't get renamed so kill-window -t tmp can properly execute.
(thx for the help and feel free to answer this so i can give you credit!)
You want allow-rename set to off, at least for that one window:
set-window-option -g allow-rename off

Resources