-2

I wrote a little service script to open an iTerm terminal window on an arbitrary folder on Finder.

I want it to check if iTerm is running, and if it is to open the terminal session in a new tab instead of on an existing one.

The script goes like this:

on run {input, parameters}

set cdPath to "cd " & (quoted form of POSIX path of (input as string))

if application "iTerm" is running then
    display notification "running"
    tell application "iTerm"
        set termWin to (current terminal)
        tell termWin
            launch session "Default"
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell
else
    display notification "not running"
    tell application "iTerm"
        activate
        set termWin2 to (current terminal)
        tell termWin2
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell
end if
return input
end run

Problem is that when I run the script as a service, it will always behave as if iTerm was already running (displaying the "running" notification), even if iTerm is closed and very clearly NOT running.

But if I paste the same script to the Script Editor (setting cdPath to a literal, like set cdPath to "cd /etc") and execute it directly it will work correctly, either opening a new iTerm instance or reusing an existing one and creating a new tab, and display the corresponding notifications.

If I simplify the script to just displaying the notifications like (removing the tell aplication block like this:

on run {input, parameters}

set cdPath to "cd " & (quoted form of POSIX path of (input as string))

  if application "iTerm" is running then
    display notification "running and path is " & cd
  else
    display notification "not running and path is " & cdPath
  end if
  return input
end run

It'll behave as expected (displaying 'running' or 'not running' accordingly).

But if I add the "tell application" part, it will always go the through "running" branch, no matter what.

E.g.:

on run {input, parameters}
set cdPath to "cd " & (quoted form of POSIX path of (input as string))

  if application "iTerm" is running then
    display notification "running"
  else
    display notification "not running"
    tell application "iTerm"
        activate
    end tell
  end if
  return input
end run

Will always open iTerm (even if the tell application "iTerm" it's on the "not running" branch, but display the "running" notification, from the "is running" branch... The mere presence of a "tell application" will trigger opening the app then the Service is run.

Is there a way to circumvent this? Why will the "tell application" block open the app even if it's on the other branch of the conditional?

yivi
  • 42,438
  • 18
  • 116
  • 138
  • What |input| is being passed to the script? Is it a string of a file path? – jweaks Nov 15 '15 at 23:10
  • When run as a service it receives a path. But I don't think it's related to the input, but with té "tell application" blocks. When I remove those, it works (although its useless), and I have it working like that in my second code block (input processed correctly). – yivi Nov 15 '15 at 23:33

2 Answers2

1

The use of "is running" is causing a run of the tell block. Use system events to get the name of running processes to check if the app is running. Here is a rewrite of your final script example that works as you wish.

on run {input, parameters}

    set cdPath to "cd " & (quoted form of POSIX path of (input as string))

    tell application "System Events" to set theProcesses to name of every process whose visible is true

    if theProcesses contains "iTerm" then
        display notification "running"
    else
        display notification "not running"
        tell application "iTerm"
            activate
        end tell
    end if
    return input
end run

If you still can't get that to work (which does on my machine running OS X 10.11.1, then you can also add the trick where you wrap any tell block inside of a run script, so it never compiles until runtime. Here's your original script, demonstrating this:

on run {input, parameters}

    set cdPath to "cd " & (quoted form of POSIX path of (input as string))

    tell application "System Events" to set theProcesses to name of every process

    if theProcesses contains "iTerm" then
        display notification "running"

        run script "tell application \"iTerm\"
        set termWin to (current terminal)
        tell termWin
            launch session \"Default\"
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell"
    else
        display notification "not running"
        run script "tell application \"iTerm\"
        activate
        set termWin2 to (current terminal)
        tell termWin2
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell"
    end if
    return input
end run
jweaks
  • 3,674
  • 1
  • 19
  • 32
  • Nope, sorry. It has the same effect than my version. Check it out in action here: https://vid.me/Wmic – yivi Nov 16 '15 at 06:26
  • It shows "running" even if iTerm wasn't really running. Found a clue here, http://stackoverflow.com/a/16071855/1426539, where it says "The act of compiling on a tell application will afaik make the app launch.", but don't know how to get around that... :( – yivi Nov 16 '15 at 06:29
  • Here is my script absolutely working. ( https://dl.dropboxusercontent.com/u/3462254/ServiceWorking.mov ) I can't read your code in the video (poor quality), so can't test it. Note that I'm testing it with TextEdit, as I don't have iTerm. You should test with TextEdit, too, to make sure iTerm is not the prob. – jweaks Nov 16 '15 at 06:52
  • Here: https://www.dropbox.com/s/xz2kl7jhcuwhyat/Automator_Failing_2.mov?dl=0 Original code whas exactly what you posted. Here I modified it to make the failing more obvious (Service first opens up closed iTerm, and immediately asks to quit) – yivi Nov 16 '15 at 07:04
  • It's not exact, cause you're running a Service based on Finder selection (that's why I earlier asked on what selection Service was activated). Do you get same behavior if you text with TextEdit? – jweaks Nov 16 '15 at 07:09
  • I'm testing with textedit now, but on folders on finder selection. It works better, but not well enough. Certainly not as I'd expect. I wouldn't expect textedit to launch if not running: https://www.dropbox.com/s/3ccrdu364msgbrr/Automator_Failing_4.mov?dl=0 – yivi Nov 16 '15 at 07:23
  • I've added an additional script to the answer showing how you would wrap your tell block in a run script, that won't compile for sure until run time and only inside that conditional. – jweaks Nov 16 '15 at 07:26
  • You say you changed and are testing on a service for "folders on finder selection". What were you doing before? – jweaks Nov 16 '15 at 07:28
  • I meant I've changed it from your version, where you receive "text on any application". Have to run to the office, I'll finish up testing later on. Many thanks! – yivi Nov 16 '15 at 07:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95216/discussion-between-jweaks-and-yivi). – jweaks Nov 16 '15 at 07:48
0

I think I found an explanation:

  • Any "is running"-phrase needs to have a short "delay" in front of it to reliably return a true answer ... but still won't do so if called as an app's service - ? because ? :
  • Furthermore I guess that Automator scripts are somehow "pre-processed" before being run as Services.
    All if-branches are evaluated (played through) and thereby activated "just in case".
    In jweaks code, iTerm is only affected directly in the 2nd clause ("tell ...").

Try this code in ScriptEditor, Automator and as Service in Safari:

display notification "" & running of application "TextEdit"
tell application "TextEdit" to activate
quit application "TextEdit"
display notification "" & running of application "TextEdit"

You will get different results from AppleScript/Automator (=> false + true) and Safari (true + true).
Especially AppleScript/Automator's true from the 2nd notification is quite telling.

... however, if you insert just a minute delay, say 0.01, after the "quit" line, running will be tested as "false" - if the script is run from within AppleScript/Automator.

clemsam lang
  • 440
  • 3
  • 11