FastScipts 3 multitasking

The FS3 multitasking is a great improvement but, sometimes, a problem for me: I often launch a script (via a keyboard shortcut) when it is already in progress. As a result, I can end up with several occurrences of the same window, waiting for user action.

Some of my scripts are applications and are therefore not affected. But most are compiled scripts or bundles that, for multiple reasons, I can’t convert into applications.

So you will have understood: I am looking for a way to prevent a script from running in FS3 if it is already in progress.

[@redsweater, if you’re in the area!]

The most immediate solution is to have each script create a temporary file that gets removed upon completion of execution. The creation of the temporary file would be upon condition that such a file did not already exist, and this condition should be life-or-death for the script.

1 Like

I’ve already thought about this kind of solution.
Save a preference (using NSUserDefault) at first run and then check it on subsequent launches.
But with more than 800 scripts, I hesitate to embark on such an adventure…
I was more thinking of an AppleEvent observer.

I have some scripts for this. I should probably clean it up as some of the below are redundant, but these work:

on pauseUntilAnyScriptIsRunning(isRunning, theTimeout)
	
	tell application "FastScripts"
		if class of isRunning is not boolean then set isRunning to isRunning as boolean
		if isRunning is true then
			set theInverse to false
		else
			set theInverse to true
		end if
		set theCount to 0
		repeat until theCount > theTimeout
			if (my scriptTaskRunningFastscripts(0)) is isRunning then return isRunning
			delay 0.1
			set theCount to theCount + 0.1
		end repeat
	end tell
	return theInverse
	
end pauseUntilAnyScriptIsRunning

on pauseUntilNamedScriptIsRunning(isRunning, scriptName, theTimeout)
	
	tell application "FastScripts"
		if class of isRunning is not boolean then set isRunning to isRunning as boolean
		if isRunning is true then
			set theInverse to false
		else
			set theInverse to true
		end if
		set theCount to 0
		repeat until theCount > theTimeout
			if (my namedScriptRunning(scriptName, false)) is isRunning then return isRunning
			delay 0.1
			set theCount to theCount + 0.1
		end repeat
	end tell
	return theInverse
	
end pauseUntilNamedScriptIsRunning

on scriptTaskRunningFastscripts(theTimeout) -- any script task
	
	tell application "FastScripts"
		set theCount to 0
		repeat until theCount > theTimeout
			if (count script tasks) > 0 then return true
			delay 0.1
			set theCount to theCount + 0.1
		end repeat
		return false
	end tell
	
end scriptTaskRunningFastscripts

on namedScriptRunning(scriptName, returnCount) -- named script task
	
	set theCount to 0
	tell application "FastScripts"
		set theTasks to (name of (script item of every script task))
		repeat with eachName in theTasks
			if (eachName as text) is scriptName then
				if returnCount is false then
					return true
				else
					set theCount to theCount + 1
				end if
			end if
		end repeat
		if returnCount is true then
			return theCount
		else
			return false
		end if
	end tell
	
end namedScriptRunning

on scriptActiveTaskCount(scriptPath) -- returns count of host script's active tasks (use `path to me as text`)
	
	tell application "FastScripts"
		set scriptTasks to every script task
		set myList to {}
		repeat with eachScriptTask in scriptTasks
			set eachPath to script file of script item of eachScriptTask as text
			if eachPath is scriptPath then set end of myList to eachScriptTask
		end repeat
	end tell
	return (count myList)
	
end scriptActiveTaskCount

on pauseUntilScriptTaskNotRunningByID(scriptTaskID, theTimeout) -- returns true if/when not running
	
	set theCount to 0
	tell application "FastScripts"
		repeat
			if theCount ≥ theTimeout then exit repeat
			set theTasks to (id of every script task)
			if scriptTaskID is not in theTasks then return true
			set theCount to theCount + 0.1
			delay 0.1
		end repeat
	end tell
	display alert "Timed out" message scriptTaskID
	return false
	
end pauseUntilScriptTaskNotRunningByID

You probably want pauseUntilNamedScriptIsRunning(false, scriptName, theTimeout).

Sorry I didn’t notice this until now. Interesting conundrum and I can see how it would be useful to be able to designate some scripts as “one at a time”. I’ll think about what I can do to improve this in a future update. And that’s an impressive approach you’ve got @p1r2c1 !

It would be perfect!

Thanks for sharing!
Will give it a try and let you know.

Thanks @p1r2c1. You gave me an idea.
Here is what I ended with:

tell application "FastScripts" to if (script file of script item of script tasks) contains ((path to me) as «class furl») then return beep

:wink:

That looks like a nice simple approach!

In fact, I forgot one thing: in real conditions (i.e. outside SD), this line will prevent the execution of the subsequent code, because the current script will always be present in the list of tasks.
So,

tell application "FastScripts" to if (count of (script tasks whose script file of script item of it = ((path to me) as «class furl»))) > 1 then return beep
2 Likes