2

I'm trying to make my Terminal change profiles when I run ssh. To this end, I wrote this script (and defined an alias so ssh would run it):

#!/bin/bash

osascript -e "tell application \"Terminal\" to set current settings \
of front window to first settings set whose name is \"AmadanRemote\""

/usr/bin/ssh "$*"

osascript -e "tell application \"Terminal\" to set current settings \
of front window to first settings set whose name is \"AmadanLocal\""

This almost does what I want. (It paints successive tabs in the same window wrong because profile is apparently window-wide, but I don't use tabs.) The issue is that if the connection closes while another Terminal window is on top, AmadanLocal profile will get applied to the wrong window.

Thus, the question: Is there any way to unambiguously identify the Terminal window or tab by the Terminal's tty device, or any other feature (instead of the fickle front window)?

If not, is there any identifying feature the first osascript invocation can return that would unambiguously identify the same window/tab in the second osascript invocation?

(Doesn't have to be AppleScript - if JavaScript makes it possible, JavaScript is fine, too.)

EDIT: If anyone is interested, the final shape of the script is:

#!/bin/bash

tty=`tty`

osascript <<EOF
tell application "Terminal"
    set W to the first window whose tty of tab 1 is "$tty"
    set T to tab 1 of W
    set the current settings of T to the first settings set whose name is "AmadanRemote"
end tell
EOF

/usr/bin/ssh "$*"

osascript <<EOF
tell application "Terminal"
    set W to the first window whose tty of tab 1 is "$tty"
    set T to tab 1 of W
    set the current settings of T to the first settings set whose name is "AmadanLocal"
end tell
EOF

Bonus: this actually does the right thing per each tab! <3

Amadan
  • 191,408
  • 23
  • 240
  • 301

1 Answers1

4

Yes, there is. In Script Editor, I can run this command:

tell application "Terminal" to get {properties, properties of tab 1} of window 1

This will get me all the properties of both the front window and its active tab. Here's the output:

{
    {
    selected tab:tab 1 of window id 15491 of application "Terminal",
    closeable:true,
    size:{550,777},
    zoomed:false,
    frame:{730,0,1280,777},
    index:1,
    visible:true,
    position:{730,23},
    class:window,
    origin:{730,0},
    name:"~ — fish  /Users/CK — ttys001",
    miniaturizable:true,
    frontmost:false,
    id:15491, <---------------------------------------① 
    miniaturized:false,
    resizable:true,
    bounds:{730,23,1280,800},
    zoomable:true
    },
    {
    font:"mononoki-Regular",
    title displays device name:true,
    cursor color:{64587,609,65480},
    current settings:current settings of tab 1 of window id 15491 of application "Terminal",
    title displays shell path:false,
    tty:"/dev/ttys001", <-----------------------------② 
    normal text color:{52428,52428,52427},
    title displays window size:false,
    title displays custom title:true,
    contents:"Last login: Mon Jun 18 04:54:37 on ttys001\nCK@CK-mac ~> ",
    row:39,
    process:{
        "login",
        "-fish"
        },
    clean commands:{
        "screen",
        "tmux"
        },
    font antialiasing:true,
    background color:{16383,16383,16383},
    title:"fish  /Users/CK",
    class:tab,
    title displays file name:false,
    history:"Last login: Mon Jun 18 04:54:37 on ttys001\nCK@CK-mac ~> ",
    selected:true,
    size:16,
    bold text color:{65535,65535,65535},
    busy status:false,
    column:60
    }
}

The first half of that output are the properties of the window, and the second half of the output are the properties of the tab in that same window.

I've labelled two properties of note with numbered arrows ① and ②.

Property ① belongs to the window, and it's the unique id of the window. This will be fixed and unchanging throughout the lifespan of the window. Therefore, at some point in your script, store the id of the front window in a variable, and reference the window through that:

tell application "Terminal"
    set wID to the id of the front window
    set visible of window id wID to false
end tell

In fact, you needn't bother with referencing the id at all if you choose to store the actual window object in a variable instead of its id:

tell application "Terminal"
    set W to the front window
    set visible of W to false
end tell

As the window object is referenced by AppleScript through the window's id value, it is equally as reliable and unchanging to do it that way.

From the list of available properties for a window, I don't see a current settings property. There is, however, a current settings property for the tab. I know you don't use tabs, but in AppleScript, each tab of Terminal in fact only belongs to one window, in a really counter-intuitive tab-window relationship.

So, a window containing three tabs should, you would expect, have an AppleScript reference to a single window object and three tab objects. Referring to them by index (which can change, so is not a good way to reference them in code), you would expect there would be tab 1 of window 1, tab 2 of window 1 and tab 3 of window 1. Instead, what you get is tab 1 of window 1, tab 1 of window 2, and tab 1 of window 3.

I have no idea why it's been implemented like that. But, essentially, the tab object and window object can seem to refer to the same framed interface that you see on screen, wishing to call it a window when in fact it might be, for certain purposes, the tab.

current settings is one of those times when you might think you're wanting to set it for the window, but you actually want to set it for the tab.

Tabs have a property, as you were hoping, called tty, which is a string value identifying the terminal that tab is using. In my case, it was "/dev/ttys001". However, as I explained just now, each window object actually only ever contains a single tab object from AppleScript's strange point-of-view. So referencing the tab is simple if you have a reference to the window containing it: it'll always be tab 1 of window id wID or tab 1 of W, however you stored your variable earlier.

But the tty property belonging to the tab can be used to reference its containing window, meaning if you know what terminal you're in, you'll always be able to identify and reference the correct tab in the correct window. And you do it like this:

tell application "Terminal"
    set W to the first window whose tty of tab 1 contains "ttys001"
    set T to tab 1 of W
    set the current settings of T to the first settings set whose name is "AmadanLocal"
end tell
CJK
  • 5,732
  • 1
  • 8
  • 26
  • You da man! I didn't know I could get the whole `properties` enumeration, that's cool! (Total newbie in AppleScript if it wasn't obvious...) – Amadan Jun 18 '18 at 07:37
  • It has some annoying features, but also some really, really nice ones. Thanks for marking my answer. – CJK Jun 18 '18 at 07:40
  • Is there a property to get the number of active terminal windows? since there could be more than one open. – SFbay007 Sep 22 '20 at 19:38
  • @SFbay007 In AppleScript, you can `tell application "Terminal" to return the number of windows` (assuming that, by _"active"_, you mean _"open"_). – CJK Sep 23 '20 at 03:43
  • Yes open. I actually found the answer. Thank you – SFbay007 Sep 23 '20 at 03:57
  • @SFbay007 Did you find it somewhere in my comment ? – CJK Sep 23 '20 at 04:26
  • Sorry. No. It is basically getting (count windows) – SFbay007 Sep 23 '20 at 05:50
  • 1
    @SFbay007 Yeah, that's the same thing. The three ways to determine the number of items in a collection, **`L`**, are: `count L`, `the number of L`, and `the length of L`. I elected to use `number` in my example because it reads the most nicely and is ok in this instance. However, `number` can be problematic in other scenarios, so it's generally best to avoid it if in doubt. Out of `count` and `length`, `length` is a property, and therefore is the most ideal way to do it. A lot of scripts online tend to favour `count` out of habit. – CJK Sep 23 '20 at 18:09