4

This is almost a code-review question, but very *nixy and more about configuration than code. For years since I switched to tmux from screen I've had a couple of nagging issues that I could not make work the way I wanted them to. Since I setup my shell to exec into a tmux session I finally decided it was time to fix this one.

By default when you attach two tmux clients to the same session, they are locked together. Switch panes in one and both switch in sync. This is different from screen where the default behavior was a shared set of panes but the client itself was independent.

What I've wanted was a way to un-bind two tmux clients attached to the same session. This is easy enough to do if you are outside of tmux and launching a new client. Just start a new session with a reference to the parent one:

tmux new-session -t original_session -s new_session

However try do do this after you are in a client and want to unlink it from whatever other client is sharing that session and things get more complicated. I tried dozens of ways and never hit on one that worked well. The closest I got was using bind <key> prompt-command ... to prompt for both the old and new session names. For whatever reason tmux does not expand the #{session_name} variable inside arguments for a new-session or prompt-command. It does in arguments to many other commands (e.g. I use it in run below) but without that expansion this particular task becomes suddenly complicated. Even with manually entering the values, it only ever sorta worked.

Today I finally got it to work. The result, however, is uglier that I would have liked. It requires a shell function to do most of the magic. In order to contain this to just the config file without involving external scripts (for dotfile portability) I'm using a hack. The config, if you crop off the first two columns, is actually executable as a shell script. With everything wrapped in functions, you can call just the part of the script you need from any keybinding. The shell script bits are comments in the config, while in shell script made the config bit is discarded with a here-doc.

Todays solution came out something like this (my full .tmux.conf file):

# : << ENDOFCONF

# Clear the default binding
unbind C-c
# Pass the name of the current session to a function to clone it
bind C-c run "cut -c3- ~/.tmux.conf | sh -s clone #S"

# ENDOFCONF
# clone () {
#   orig=${1%-*}
#   copy="$orig-$(($( tmux list-sessions -F '#S' | sed -nE "/^${orig}-[0-9]+$/{s/[^0-9]//g;p}" | tail -n1 )+1))"
#   TMUX= tmux new-session -d -t $orig -s $copy
#   tmux switch-client -t $copy
#   tmux set -q -t $copy destroy-unattached on
# }
# $@

Mind you this works. From a running tmux client, Ctrl+B Ctrl+C creates a new session with a number appended to the name of the current one, uses the current one as a target for the panes, and switches to it.

I'm happy with this except for the nagging idea that I've just made something simple much more complex than it needs to be. Is there a simpler way to achieve this?

  • could you not just bind keys to the source-file command? Also, what is the word elegant supposed to mean anyway? I've seen it before, but in the context of computing - in which everything, even addition, is a brute-force trial-and-error affair - I've never thought it had any place. – mikeserv Jun 22 '14 at 0:56
  • I think any answer on that score would have to be one based on opinion. Can you edit this question to clarify that? – mikeserv Jun 22 '14 at 1:05
  • @mikeserv What exactly would go in the sourced file? If I can't get this to work inside the normal config, why would sourcing another one make a bean of difference? As for what is "elegant", the vast majority of this site involves some degree of opinion as "better" solutions are offered that are some combination of simpler, more robust, faster or just use other tools. I think our community is quite capable of interpreting this in a constructive way based on the detail I've given. A solution that used tmux native config options without out-sourcing to a script would be a logical place to start. – Caleb Jun 23 '14 at 9:27
  • @mikeserv I'm sorry if my question is not clear but it's the best articulation I can come up with. Meanwhile your proposed solutions here and in chat make it pretty clear that you don't understand the problem I am trying to solve. I would appreciate this being left for somebody that at least recognizes the particular issue involving linked and unlinked session sharing in different clients. – Caleb Jun 23 '14 at 9:50
  • So yeah - it looks like orig=$(tmux display-message -p '#{session_name}') ; orig=${orig%-*} ... run from the session you want to unlink/clone should do the trick. You should be able to adapt that into something you can just use source-file on. The rest should just be the same, I guess. But you don't have to do that recursive thing. Still, even if you did, you could have just attached the here-doc to the function itself like fn() (set -- $sname ; orig=${1%-*} ... ) <<CONF\n${sname=$(tmux run ...)}\nCONF\n – mikeserv Jun 23 '14 at 11:18
0

This is what I did:

alias ta='export NEW_SESSION=\$(uuidgen) ; tmux new-session -t 0 -s \$NEW_SESSION ; tmux kill-session -t \$NEW_SESSION'

What this does is create a new session from session named '0' (what the first session is named if you don't specify), named something uniquely random (using uuidgen) and then kill it when I detach.

Note that I'm using zsh. 'ta' is short for 'tmux attach'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.