Tilix: Change profiles for ssh machines (triggered profile changing)

Created on 13 Mar 2016  Â·  36Comments  Â·  Source: gnunn1/tilix

A coworker was recently showing me how he uses different terminal profiles to give himself quick cues about what machine the terminal is on - eg a dev VM, staging server, production server. It would be neat if terminix could be triggered to do things based on the terminal prompt or something of that nature. Then, I could change the background color when the terminal changes hostname in a ssh session.

I can imagine this might be useful for other things as well, depending on how generically it gets implemented!

enhancement

All 36 comments

It's on my radar but it requires an enhancement in the VTE widget Terminix is using as per this bug report:

https://bugzilla.gnome.org/show_bug.cgi?id=734823

Until then, the background color can be changed by the OSC 11 escape sequence, e.g.:
echo -ne '\e]11;#ddeeff\a'

@egmontkob Can you give me an opinion on an idea I have based on your experience with the VTE please. The VTE already returns a hostname as part of the window title as far as I can tell and it does this through an OSC 7 code I believe. As long as the machine you are SSH'ing into has sourced the vte.sh file I assume that you will start getting a new hostname in the window title at that point.

Could I drive this feature off of that by simply parsing out the hostname from the window title and reacting to changes to it?

Nice idea...

To clarify: OSC 0 sets the window title, OSC 7 sets the concept of the current working directory (to be used when opening a new tab). Both are set by vte-2.91.sh, although there are pending vte bugs to remove the window title stuff from here. Also it's modified by many users. OSC 7 is something you could more safely rely on.

I've no clue if you can subscribe to be notified when this string changes. Let me know please if you figure it out :)

Wow, really nice idea! :) How come it didn't occur to us?

If you can't get notified when this string changes, you could still poll it once per sec or so.

@egmontkob I'd prefer to avoid polling but I think I should be notified via the VTE title change events, I'll play around with it. If it works out, I'll probably look at adding something to manage SSH connections and include this as an option to that.

One problem you'll face is that vte.sh ckecks for $VTE_VERSION which is not forwarded by ssh. So you'll have to ask your users to set up emitting OSC 7 from the remote machine.

... and of course the remote system might not even have vte installed.

Yeah, the idea would be to ship an optional script file that could be installed on remote machines like iterm2 does. This is what was I planning on doing when I bite the bullet to learn enough C to write a VTE patch for custom OSC sequences as per 734823.

Anyone know of any terminals with good SSH/telnet integration to base this feature off of? I know the OSX terminal allows you to create remote connections, any others that would be worth looking at for implementation ideas?

What's your goal exactly?

If you're planning a nice UI for choosing where to connect to, probably Putty is the most popular solution.

I though this issue was about automatically detecting and changing the profiles when the user types "ssh remotehost", but without offering any help doing this.

I'm excited to see what you have in your mind :)

Yes it is, but since it needs a UI I was debating about between incorporating it into a bookmark manager type functionality versus an extra tab in the profile. Unfortunately, after looking around I don't see a good implementation of bookmarks anywhere and I don't have a compelling vision for it. Couple with the fact I like the way iterm2 does it means I'll probably just start with a basic version of that as it should be fairly easy to implement.

https://iterm2.com/automatic-profile-switching.html

Sure, I see. I don't have a Mac to check iTerm now. A few questions/issues that randomly occur to me:

  • If you piggyback on OSC 7 (hostname + current directory) then you'll only be able to select on hostname (or current directory but that's unlikely to be useful), not on the username.
  • Would it be a finite state machine (only the current profile remembered), or a stack remembering where we came from? In the latter case, an unrecognized hostname (or the hostname of the host where Terminix is running, with a bit of looseness wrt. hostname only vs. fqdn) could revert to the previous profile that was used before ssh'ing.
  • Maybe somewhere in between: More than just the current profile remembered, but less than an arbitrarily large stack: Just remember the one profile originally chosen by the user, and one override according to OSC 7's hostname. Whenever a hostname appears in OSC 7 that doesn't match any profile's setting, you'd revert to the original profile.

iTerm's UI seems to be a great compromise to me, focusing primarly on the UI's simplicity, yet being probably flexible enough for the typical use cases.

I was thinking of driving it off the VTE event window-title-changed which I believe is emitted from OSC 7, as far as I can tell it gives you the user as well as the hostname and directory as you mentioned in the form of user@hostname:directory. Parse that out into it's components and you basically have what is needed to drive this feature and do what iterm2 is doing.

My plan is to keep the implementation simple for now, so I would be following what you described in the third bullet. If no rule matches the current user, hostname and directory it would simply revert to the original profile.

I'm afraid you're still mixing up the two escape sequences (which have nothing to do with each other apart from vte.sh configuring PROMPT_COMMAND to emit both, which is a bad design I'd like to address one day, see Gnome bugs 743073, 709358 and 704960).

OSC 0 sets the window title (to whatever arbitrary string you want to), and accordingly, emits a window-title-changed. vte.sh sets this up to contain the username, hostname and directory. However, it's reasonable to expect that many people modify this according to their own taste, maybe even stop bash's prompt from tampering with the window title. Hence, while technically it's possible to parse this value and rely on this, this is a very fragile approach.

OSC 7 sets the terminal's belief about the hostname and current working directory (no username here), and accordingly, emits a directory-uri-changed. Since it has a well-defined syntax and semantics, it's reasonable to expect that you can count on its contents (if it's being emitted at all by the remote host).

Thanks for the clarification, that's disappointing since user is an obvious filter to include for profile switching and one that is actually more useful to me personally then hostname since I'm more of a developer then an administrator. Thanks for the bug reports, reading them is illuminating and makes it clear why relying on window title alone is a bad idea.

The options I see with respect to user is as follows:

  • Check the title in window-title-changed and if it conforms to the expected format then use it, otherwise fallback to the directory-uri-changed event. Probably a bit challenging since the events are emitted separately.
  • Use the hostname:directory instead of user@hostname:directory format like iterm2 does. Once I get time to work on patching VTE to support custom OSC codes then re-visit it.

I think I'll go for the second option for now.

Second one sounds better to me too.

Wait a bit... the syntax for OSC 7 is "file://hostname/path", I wonder what happens if someone uses "file://username@hostname/path" instead, which might also be a valid URI, I don't know if it's allowed for the "file" scheme (it is sure allowed for "http", and probably it's scheme agnostic).

Yet another vte/g-t bug: 709055. Currently the hostname is ignored, whereas it should be compared with localhost's hostname and the path ignored in case of mismatch.

@gnunn1 Action plan: You have access to a Mac, don't you? If so, could you please try these in Mac's default Terminal.app:

1.

echo -e '\e]7;file://hostname/tmp\a'; sleep 10000

whereas hostname is replaced by the actual hostname, and /tmp is an existing directory different from the current dir.

Open a new tab. Expected: It opens in /tmp. Is this the case?

2.

Change the hostname to something else:

echo -e '\e]7;file://someotherhostname/tmp\a'; sleep 10000

Expected: new tab opens in your current directory, and not in /tmp. Okay so far?

3.

Revert the hostname, and add a username:

echo -e '\e]7;file://someusername@hostname/tmp\a'; sleep 10000

Where does the new tab open now?

@egmontkob Step 1 doesn't work, the OSX terminal always opens a new tab in my home directory. I have a feeling you are a step ahead of me as I'm confused, what does it matter how the OSX terminal behaves?

Output from the terminal of the different variations I tried:

Geralds-MacBook-Pro:~ gnunn$ echo $HOSTNAME
Geralds-MacBook-Pro.local
Geralds-MacBook-Pro:~ gnunn$ echo -e '\e]7;file://Geralds-MacBook-Pro.local/tmp\a'; sleep 10000
\e]7;file://Geralds-MacBook-Pro.local/tmp
^C
Geralds-MacBook-Pro:~ gnunn$ echo -e '\e]7;file://Geralds-MacBook-Pro.local/tmp\a'; sleep 10000
\e]7;file://Geralds-MacBook-Pro.local/tmp
^C
Geralds-MacBook-Pro:~ gnunn$ echo -e '\e]7;file://Geralds-MacBook-Pro/tmp\a'; sleep 10000
\e]7;file://Geralds-MacBook-Pro/tmp
^C

Geez, I forgot that Mac's echo doesn't support -e. Could you please figure out the equivalent? (Perhaps echo $'\e]7;blah\a' – does this work?) These commands shouldn't output anything (and changing 7 to 0 should set the window title).

OSC 7 was introduced by Mac's Terminal.app, hence I consider that the reference implementation. I wonder how it handles if a username is also added there.

I used printf instead of echo -e, in all three cases it opened the tab in /tmp

I also tested it with SSH to a centos 7.2 VM, when you include the username VTE doesn't pass it up to the application. Without the username it works fine.

This means that Terminal.app also suffers from bug 709055, and as such there's absolutely no point in using an URI scheme with the hostname included, a simple path would have been just as good.

So, users (who have to explicitly set this stuff on remote machines, pretty much like iTerm's shell integration) are free to fake whatever hostname they'd wish, should there be a need to distinguish multiple users on a given host. E.g. they can prefix the hostname with "username@" and this won't cause any behavioral change (if I understand correctly), except that they'll be able to select on this in Terminix's automatic profile change settings.

@egmontkob Wouldn't the VTE require a patch for this though? When I SSH into a centos VM and print the OSC 7 signal with the user@hostname:directory format, the current_directory_uri I retrieve from VTE does not change. For example, if I print:

printf '\e]7;file://centos70/tmp\a'

The VTE reports the current_directory_uri as file://centos70/tmp as expected.

However, if I then print printf '\e]7;file://gnunn@centos70/test\a', VTE doesn't recognize the directory change to test and as a result doesn't return the username as part of the uri so I'm not sure how I would even pick that up?

Yup, you're right. Damnit.

According to rfc1738 (search for "fileurl" to see the BNF) and g_filename_from_uri() (which is used by VTE), file:// URLs might contain a hostname only, but not a username. Gosh. Forget this approach, then :(

My recommendation is to implement switching based on the hostname only (as seen via OSC 7), until the way more generic method is implemented.

Users who really need to switch profile based on the user might hack it around by faking different hostnames based on the username, although this is a hack I wouldn't ship out of the box.

@egmontkob As discussed above, I'll support switching on hostname and directory, once I get around to adding that patch for a custom OSC sequence to VTE I'll look at expanding it unless a certain VTE maintainer I know wants to work on this _nudge, nudge, wink, wink_ :)

@egmontkob as an FYI, I've checked in some very rough progress on this issue, it's turned off by default via a compile flag in constants.d and I wouldn't recommend testing it at this point.

As a note to myself and an FYI for you in case you have thoughts, initial testing shows a number of issues that have to be addressed as follows:

  • If we want to optionally use the /etc/profile.d/vte... script to drive this, particularly for later VTE versions, the VTE_VERSION environment variable would need to be explicitly set within the SSH session. Using a custom script is a possibility as well but need to be sure we don't accidentally double up the prompt command.
  • If you are SSH'ed into a remote machine, since we now get hostname/directory changes creating a new tab or session, while local, will use the directory of the remote SSH session. Terminix should remember the last local directory based on comparing the hostname in the event to the hostname in Terminix's environment variables which will be the local one. A fair amount of internal plumbing needs to be changed for this one, I'm thinking certain things need to be moved into a new state (hostname, directory, etc) struct with two copies, one for the local state and one for the remote state.
  • If automatic profile switching is active, don't allow the user to select a new profile from the terminal titlebar.

Respectively for your bullet points:

  • I'd probably go for setting up independently from vte.sh (since that might not be installed on the remote host). Propagating VTE_VERSION is also tricky. Or faking one (but that goes against the point). Or parse the "response" (which is injected as if it was typed by the user) to \e[>c which is again tricky from shell script, is unreliable (racy since a timeout is needed against emulators that don't support it, and then ssh might be too slow and this timeout kick in even with VTE), wipes out the typeahead, and needs heuristics to tell VTE from other terminals.
  • You're right. Furthermore, we should double check whether VTE emits a signal for all OSC 7s if it sees more of them in a row, rather than optimizing and just emitting for the last. In the latter case VTE needs to be reworked.
  • I don't think I'd disable it.

Filed vte bug 767313 (note that this bug is unlikely to occur during normal terminal usage and so probably shouldn't block you).

Note for the second bullet point I added some code to Terminix to remember the last hostname/directory and only propagate it if it is different.

As for the third point, I think it would be weird from a UI perspective to allow the user to switch away from an active automatic profile since as soon as they change directory it will switch back to that. If the profile radio buttons were to switch the default profile (i.e. the one used when automatic profile is not active), I think users would find it confusing since no profile change would actually happen until the condition driving the automatic profile changed and the default reverted.

Personally I don't think that last point matters overly much as I don't get the impression that manual profile switching is used much since it was accidentally disabled for a few weeks at one point and no one complained :)

You're right, I keep forgetting directory change as a use case, only have ssh in my mind.

I've checked in a version now that is mostly working and have went ahead and removed the compile flag so it can be tested. I'm aware of the following outstanding issues still to be addressed:

  • I haven't disabled profile selection yet when the automatic profile is enabled
  • The directory matching is literal whereas it should probably match such that subdirectories are included as a match. i.e., having a match value of /home/gnunn/Development should match home/gnunn/Development/terminix whereas now it does not
  • Need to support tilda expansion for the directory
  • If you have SSH'ed to a remote host and create a new tab/session, it uses the local directory now but inherits the automatic profile rather then the default profile.
  • The new script terminix_int.sh that modifies PROMPT_COMMAND should append the command to it rather then replace it
  • ZSH is completely untested at this point.

There is a new file data/scripts/terminix_int.sh that needs to be sourced on remote machines. I tested it with SSH by putting in .bashrc . /home/gnunn/Development/terminix/data/scripts/terminix_int.sh and it seems to work fine. This file is a cribbed version of vte.sh and it's handling of osc7 with some minor modifications including checking if vte already set the prompt command and avoids doubling up on it.

Note my bash skills are pretty weak, I'm sure it can use some improvement so if anyone is super skilled at bash and wants to have a look feel free.

Anyway, while I'm sure we will go through a process of bug-fixing as usual it's a good start. I'll do some more work on this tomorrow and hopefully close the remaining issues I identified above.

The last commit fixes the remaining issues, I'm quite happy with how well this feature worked out. Hopefully when I get to working on the VTE and adding support for custom OSC sequences I can add support to this for triggering on the user as well.

I'll do a write-up on the wiki on how this feature works later today.

Wiki entry added here:

https://github.com/gnunn1/terminix/wiki/Automatic-(Triggered)-Profile-Switching

FYI: I've written a small tool that uses SSH's LocalCommand and small script to change the terminal background color when SSHing to a machine. It does not require any remote configuration. You can find it here: https://github.com/fboender/sshbg

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vaijab picture vaijab  Â·  3Comments

sirex picture sirex  Â·  3Comments

sliddjur picture sliddjur  Â·  3Comments

huti26 picture huti26  Â·  3Comments

gregflynn picture gregflynn  Â·  4Comments