Applescript (osascript): opening split panes in iTerm 2 and performing commands
Asked Answered
T

6

13

The following works to open two tabs in iTerm 2.

I can't seem to figure out how to get this to using split panes instead.

I've tried applying what I see on several forums, but it never works. Could someone point me in the right direction?

osascript <<-eof
        tell application "iterm"
                set myterm to (make new terminal)
                tell myterm
                        launch session "Default session"
                        tell the last session
                                set name to "Server"
                                write text "cd $projectsFolder"
                        end tell
                        launch session "Default session"
                        tell the last session
                                set name to "Console"
                                write text "cd $projectsFolder"
                        end tell
                end tell
        end tell
eof
Taster answered 11/3, 2014 at 23:59 Comment(0)
T
0

Okay, so I finally figured this out.

By sending keystrokes to the application, you can open and navigate split-pane.

tell i term application "System Events" to keystroke "D" using command down

tell i term application "System Events" to keystroke "]" using command down

An example sending commands to split pane and naming each pane. I use this to start my node application.

write text "cd $projectsFolder/$2.m"

write text "/usr/local/bin/frontend.sh $1 $2"

tell i term application "System Events" to keystroke "D" using command down

tell i term application "System Events" to keystroke "]" using command down

set name to "$2.api"

write text "cd $projectsFolder/$2.api"

write text "/usr/local/bin/backend.sh $1 $2"
Taster answered 29/3, 2014 at 1:55 Comment(6)
Did you include the tokens i term by accident?Pocketknife
No, I didn't, @mklement0.Taster
Thanks; I've since realized that this actually works when enclosed in a tell application "iTerm" block. I was thrown by the unusual syntax - seems that iTerm itself prepends i term application to the application name when you compile a tell application ... statement inside a tell application "iTerm" block. An equivalent form (with an explicit activate command to ensure that the keystrokes are sent to iTerm) would be: tell application "iTerm" to activate, followed by tell application "System Events" to keystroke "D" using command down.Pocketknife
Ah, okay. I haven't actually compiled any of this, it's just included in a bash script I'm working on.Taster
Got it; if the intent is to return to the previously active pane, you're better off sending "[" rather than "]" - that way, it'll work even when there's already more than 1 pane.Pocketknife
I encourage you to remove the i term application from the tell i term application "System Events" statements: your code will run without them and, most importantly, will continue to run if/when the underlying problem is fixed in iTerm (as I said: AppleScript editor will insert the i term application when you compile, but that doesn't apply in your case, since you're passing source code directly to osascript).Pocketknife
P
34

With the new nightly build it is quite nice. It seems to be missing in the public version, although it was implemented about a year ago: Source - AppleScriptTest.m

tell application "iTerm"
    activate
    select first window
    
    # Create new tab
    tell current window
        create tab with default profile
    end tell
    
    # Split pane
    tell current session of current window
        split vertically with default profile
        split vertically with default profile
    end tell
    
    # Exec commands
    tell first session of current tab of current window
        write text "cd ~/Developer/master-node"
        write text "coffee"
    end tell
    tell second session of current tab of current window
        write text "gulp w"
    end tell
    tell third session of current tab of current window
    end tell
end tell

I had to search way too long for this, so maybe I can help somebody out with this (probably myself in a couple of weeks), because this was one of the first things I found. This solution even works with activated focus-follows-mouse, which is missing in the other answers.

Paunch answered 14/2, 2015 at 3:55 Comment(3)
This worked for me. I did have to change select first terminal window to select first windowFloorwalker
Pasted the exact code into apple script editor and it gives me "error "iTerm got an error: Can’t get current window of window id 35415." number -1728 from current window of window id 35415"Smokeless
Confirmed this still works on macOS 12.6, and edited the example to apply the fix suggested by @DennisBestEarthling
J
11

As Dom pointed out, in the new 2.9 beta builds, the other answers won't work anymore. I was frustrated by not being able to automated this so I wrote a teamocil compatible command line tool that does exactly this:

https://github.com/TomAnthony/itermocil

It allows you to write YAML files for pre-configured sets of windows and panes, which can run pre-defined sets of commands for the given project.

Joost answered 13/8, 2015 at 18:3 Comment(1)
many thanks !! <!-- language: lang-applescript --> tell application "iTerm" create window with default profile tell current session of current window write text "bash itermocil log" end tell end tell <--Bedtime
P
5

Update: iTerm2 v3 has much-improved, but incompatible AppleScript support - see https://www.iterm2.com/documentation-scripting.html

To provide some background to @Joel's own answer:

iTerm 2's AppleScript support (as of iTerm 2 v1.0.0.201306220):

  • is incomplete: there is no support to script split panes - hence the OP is resorting to the suboptimal technique of sending keystrokes.

  • exhibits some bizarre behavior: when compiling (in AppleScript Editor) a tell "System Events" ... statement inside a tell application "iTerm" block, the prefix i term application is inexplicably inserted before the "System Events" - since the code below is not precompiled, this prefix is not included so as to avoid problems in the future.

  • has bugs / is inconsistent with its dictionary: what the dictionary describes as the exec command - which doesn't actually work - is in reality fulfilled by the write text command: it executes the argument passed or - if the argument has a trailing space - simply "types" the argument without submitting it.

Here's the solution with split panes based on the workaround (sending keystrokes) - a bash script invoking AppleScript code via osascript:

Limitations, due to panes not being part of the dictionary:

  • the other pane that is opened cannot be named
  • no command can be sent to the other pane
#!/usr/bin/env bash

projectFolder="$HOME/Desktop" # example
osascript <<-EOF
  tell application "iTerm"
    tell (make new terminal) # Create a new pseudo terminal...
      tell (launch session "Default session") # ... and open a session (window)
        # Name the new window (its original pane).
        set name to "Server"
        # Execute the 'cd' command in the original pane.
        write text "cd '$projectFolder'"
        # Create a new split pane, horizontally, by sending ⌘⇧-D 
        tell application "System Events" to keystroke "d" using {shift down, command down}
          # !! Note: We canNOT:
          #  - name this pane separately
          #  - execute a command in it.
        # Return to the original pane, by sending ⌘-[ 
        tell application "System Events" to keystroke "[" using {command down}
      end tell
    end tell
  end tell
EOF
Pocketknife answered 31/3, 2014 at 2:16 Comment(2)
Mostly correct @mklement0, but you can name each pan and send keystrokes to the other pane. I updated above.Taster
@Joel: Hmmm... That doesn't work for me. Looking at the logic of your updated code, you perform all your operations in the original pane (since the name and the other group of write commands are performed after sending ⌘-], which causes you to return to the original pane). Am I missing something? What iTerm version are you using?Pocketknife
S
2

starting from @mklement0, this is my script that open a new tab, split in 4 panels and run comands:

#!/usr/bin/env bash
osascript <<-EOF
    set cmds to {"rabbitmq-server", "mongod", "redis-server", "htop"}

    tell application "iTerm"
        activate
        set myterm to (current terminal)

        tell myterm
            launch session "Default Session"

            # split vertically
            tell application "System Events" to keystroke "d" using command down
            delay 1
            # previus panel
            tell application "System Events" to keystroke "[" using command down
            delay 1
            # split horizontally
            tell application "System Events" to keystroke "d" using {shift down, command down}
            delay 1
            # next panel
            tell application "System Events" to keystroke "]" using command down
            delay 1
            # split horizontally
            tell application "System Events" to keystroke "d" using {shift down, command down}

            set n to count of cmds
            repeat with i from 1 to n
                # next panel
                tell application "System Events" to keystroke "]" using command down
                delay 1
                tell the current session to write text (item i of cmds)
            end repeat
        end tell

    end tell  
EOF
Stuart answered 2/7, 2015 at 11:33 Comment(0)
B
1

In case it's helpful: I have the similar problem of wanting a key combo shortcut in iTerm to split panes and have the new pane inherit the title of the original session. I came up with the following, which solves that problem and relies less on sending keystrokes (though I'd love to eliminate them entirely).

tell application "iTerm"
    tell the current terminal
        tell the current session
            set the_name to get name
            tell i term application "System Events" to keystroke "d" using {command down, shift down}
        end tell

        tell the current session
            set name to the_name
        end tell
    end tell
end tell

I am using BetterTouchTool to bind a key combo -- namely, cmd+' -- to the execution of this AppleScript. (I find that it gets screwy for some key combos, I would naively guess because you are effectively holding that key combo down on top of whatever keystrokes the script sends. I haven't chased down how to define the keyboard shortcut in the preferences of iTerm itself. I suspect that might mitigate the issue.)

Buck answered 25/9, 2014 at 2:40 Comment(0)
T
0

Okay, so I finally figured this out.

By sending keystrokes to the application, you can open and navigate split-pane.

tell i term application "System Events" to keystroke "D" using command down

tell i term application "System Events" to keystroke "]" using command down

An example sending commands to split pane and naming each pane. I use this to start my node application.

write text "cd $projectsFolder/$2.m"

write text "/usr/local/bin/frontend.sh $1 $2"

tell i term application "System Events" to keystroke "D" using command down

tell i term application "System Events" to keystroke "]" using command down

set name to "$2.api"

write text "cd $projectsFolder/$2.api"

write text "/usr/local/bin/backend.sh $1 $2"
Taster answered 29/3, 2014 at 1:55 Comment(6)
Did you include the tokens i term by accident?Pocketknife
No, I didn't, @mklement0.Taster
Thanks; I've since realized that this actually works when enclosed in a tell application "iTerm" block. I was thrown by the unusual syntax - seems that iTerm itself prepends i term application to the application name when you compile a tell application ... statement inside a tell application "iTerm" block. An equivalent form (with an explicit activate command to ensure that the keystrokes are sent to iTerm) would be: tell application "iTerm" to activate, followed by tell application "System Events" to keystroke "D" using command down.Pocketknife
Ah, okay. I haven't actually compiled any of this, it's just included in a bash script I'm working on.Taster
Got it; if the intent is to return to the previously active pane, you're better off sending "[" rather than "]" - that way, it'll work even when there's already more than 1 pane.Pocketknife
I encourage you to remove the i term application from the tell i term application "System Events" statements: your code will run without them and, most importantly, will continue to run if/when the underlying problem is fixed in iTerm (as I said: AppleScript editor will insert the i term application when you compile, but that doesn't apply in your case, since you're passing source code directly to osascript).Pocketknife

© 2022 - 2024 — McMap. All rights reserved.