##bug Report: AppleScript Fails When Run from File
Running Keyboard Maestro 7.3.1 (7.3.1) on macOS 10.11.6
There appears to be a bug somewhere (not sure where) that causes the AppleScript in the below Macro to fail when it is run from a file.
Runs fine as text
Runs fine from Script Editor 2.8.1 (183.1)
Runs fine from Script Debugger 6.0.4 (6A198)
I have created a new macro from scratch in another Group, but it still fails.
Error Msg:
/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 4888 of " ". (-1728)
Sorry, but it is a long script:
The original (which also fails) was written by @ccstone. I made some minor mods to output path of selected UI element.
###Purpose
* Scan the Frontmost Window UI to produce a report of all UI Elements.
* Provide the UI Path to a Chosen Element
**Notice: This script requires [Satimage.osax](http://www.satimage.fr/software/en/downloads/downloads_companion_osaxen.html).**
```applescript
--~~~~~~~ CLEAN SAVE IN SCRIPT EDITOR ~~~~~~~~~~
--------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/06/11 05:40
# dMod: 2016/06/13 15:01
# Appl: System Events
# Task: Report System Events UI Information for the Front Window of the Front app.
# Libs: None
# Osax: None
# Aojc: True
# Tags: @Applescript, @Script, @System_Events, @Analyze, @Front, @Window
# Vers: 1.50
#
# REQUIRES: Satimage.osax
# http://www.satimage.fr/software/en/downloads/downloads_companion_osaxen.html
--------------------------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
property LF : linefeed
--------------------------------------------------------------------------------
# If you haven't changed your default text editor these two options will be eqivalent.
property outputType : "Default Text Editor" --> Alternative: "TextEdit"
--------------------------------------------------------------------------------
set tabPad to " "
tell application "System Events"
set frontProcess to first process whose frontmost is true
tell frontProcess
set processName to its name
tell front window
set windowName to its name
set entireContentsOfWindow to entire contents
set winSubRole to subrole
end tell
try
goofy of entireContentsOfWindow
on error forcedErrorText
end try
end tell
end tell
set AppleScript's text item delimiters to {"{", "}"}
set forcedErrorText to text item 2 of forcedErrorText
set forcedErrorText to its cngStr:" of application process \"[^\"]*\" of application \"[^\"]*\"(?:, )?" intoString:linefeed inString:forcedErrorText
set forcedErrorText to paragraphs of forcedErrorText
copy forcedErrorText to elemList
##return forcedErrorText
repeat with theLine in forcedErrorText
set tabCnt to ofCount(theLine)
set tempText to (its cngStr:" \\bof\\b.+" intoString:"" inString:theLine)
if tabCnt > 0 then
set tempText to text 1 thru tabCnt of tabPad & tempText
end if
set contents of theLine to tempText
end repeat
set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
set forcedErrorText to forcedErrorText as text
set AppleScript's text item delimiters to oldTIDS
set forcedErrorText to "application Process \"" & processName & "\"" & linefeed & ¬
tab & "window " & windowName & linefeed & ¬
forcedErrorText
--------------------------------------------------------------------------------
--» OUTPUT
--------------------------------------------------------------------------------
--set the clipboard to forcedErrorText
set AppleScript's text item delimiters to linefeed
set reportStr to change tab into " " in forcedErrorText
set reportList to text items of reportStr
set AppleScript's text item delimiters to oldTIDS
set frontApp to path to frontmost application as text
tell application frontApp
set elemSel to choose from list reportList
end tell
if (elemSel ≠ false) then
set elemPos to (my getItemPos(elemSel, reportList)) - 2
set AppleScript's text item delimiters to ""
## (elemPos & ": " & elemSel as text)
set elemPath to (item elemPos of elemList) as text
set winWhose to "(first window whose subrole is \"" & winSubRole & "\")"
set elemPath to change "window .+$" into winWhose in elemPath with regexp
set scriptResults to "PATH TO SELECTED ELEMENT:" & LF & elemPath & LF & LF & reportStr
else -- Choose List was Canceled --
set scriptResults to reportStr
end if
return scriptResults
--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------
on getItemPos(pItemToFind, pListToSearch)
if (class of pItemToFind = list) then set pItemToFind to item 1 of pItemToFind as text
repeat with i from 1 to count of pListToSearch
if item i of pListToSearch is pItemToFind then return i
end repeat
return 0
end getItemPos
on cngStr:findString intoString:replaceString inString:dataString
set anNSString to current application's NSString's stringWithString:dataString
set dataString to (anNSString's ¬
stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------------------------------
on createDirectoryAtPath:thePath
set {theResult, theError} to current application's NSFileManager's defaultManager()'s createDirectoryAtPath:thePath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
if not (theResult as boolean) then
set errorMsg to theError's localizedDescription() as text
error errorMsg
end if
end createDirectoryAtPath:
--------------------------------------------------------------------------------
# Open in default editor for text files set in the Finder Get-Info window.
--------------------------------------------------------------------------------
on outputToDefaultTextEditor(_text)
set dirPath to POSIX path of (path to temporary items from user domain as text)
set filePath to dirPath & "Window_UI_Exploration.txt"
its createDirectoryAtPath:dirPath
its writeString:_text toPath:filePath
set shCMD to "
open -t " & qf(filePath) of me
do shell script shCMD
end outputToDefaultTextEditor
--------------------------------------------------------------------------------
on ofCount(_text)
set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " of "}
set theCount to length of (text items of _text)
set AppleScript's text item delimiters to oldTIDS
return theCount
end ofCount
--------------------------------------------------------------------------------
on outputToTextEdit(_text)
do shell script "echo " & qf(_text) of me & " | open -f"
end outputToTextEdit
--------------------------------------------------------------------------------
on qf(_text)
return (quoted form of _text)
end qf
--------------------------------------------------------------------------------
on writeString:aString toPath:posixPath
set anNSString to current application's NSString's stringWithString:aString
anNSString's writeToFile:posixPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeString:toPath:
# Other encodings: NSMacOSRomanStringEncoding
--------------------------------------------------------------------------------
```
###MACRO: @TEST @AppleScript UI Elem
~~~ VER: 1.0 2017-06-15 ~~~
####DOWNLOAD:
<a class="attachment" href="/uploads/default/original/2X/0/01b53c886b16ebfb162f8095726ffb8592563a83.kmmacros">@TEST @AppleScript UI Elem.kmmacros</a> (15 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**
---
###Use Case
*
---
###ReleaseNotes
/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 4888 of " ". (-1728)
---
<img src="/uploads/default/original/2X/b/b34143ed5ac2fcccf5a0201473b033aacba50f9c.png" width="448" height="979">
I didn’t try it - I don’t usually run scripts and you didn’t even say what it does, so without looking at it closely I wouldn’t even know if I had whatever apps it needs, or when to run it or what setup it needs.
In any event, Keyboard Maestro runs AppleScript files the same way it runs AppleScript text:
osascript /path/to/file
So if it is a script file, that should get the same result unless it is somehow dependent on the inherited environment of Keyboard Maestro Engine.
The error you show is a syntax error, quite different from the execution error I'm reporting when run from KM.
I believe the error you are seeing may be because you do not have the Satimage.osax installed. My fault for not making this requirement clear at the top of the script.
/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: System Events got an error: osascript is not allowed assistive access. (-1719)
But after giving Terminal Accessibility permission, I now get the same error as when run from KM:
> /Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 38 of " ". (-1728)
And I get same error (but different text range) when run from FastScripts:
FWIW, I get the same error when I run Chris' (@ccstone) original script from file:
/Users/Shared/Dropbox/SW/DEV/KM/Scripts/Window Analysis Tool for System Events v1.50 @ccstone@AS.scpt: execution error: Can’t get text 1 thru 357 of " ". (-1728)
###Original Script by @ccstone
I could be wrong, but I think that this script does NOT require/use Satimage.osax.
It builds a list of UI elements of the frontmost window, and then opens the list in either BBEdit or TextEdit.
--------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/06/11 05:40
# dMod: 2016/06/13 15:01
# Appl: System Events
# Task: Report System Events UI Information for the Front Window of the Front app.
# Libs: None
# Osax: None
# Aojc: True
# Tags: @Applescript, @Script, @System_Events, @Analyze, @Front, @Window
# Vers: 1.50
--------------------------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
--------------------------------------------------------------------------------
# If you haven't changed your default text editor these two options will be eqivalent.
property outputType : "Default Text Editor" --> Alternative: "TextEdit"
--------------------------------------------------------------------------------
set tabPad to " "
tell application "System Events"
set frontProcess to first process whose frontmost is true
tell frontProcess
set processName to its name
tell front window
set windowName to its name
set entireContentsOfWindow to entire contents
end tell
try
goofy of entireContentsOfWindow
on error forcedErrorText
end try
end tell
end tell
set AppleScript's text item delimiters to {"{", "}"}
set forcedErrorText to text item 2 of forcedErrorText
set forcedErrorText to its cngStr:" of application process \"[^\"]*\" of application \"[^\"]*\"(?:, )?" intoString:linefeed inString:forcedErrorText
set forcedErrorText to paragraphs of forcedErrorText
repeat with theLine in forcedErrorText
set tabCnt to ofCount(theLine)
set tempText to (its cngStr:" \\bof\\b.+" intoString:"" inString:theLine)
if tabCnt > 0 then
set tempText to text 1 thru tabCnt of tabPad & tempText
end if
set contents of theLine to tempText
end repeat
set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
set forcedErrorText to forcedErrorText as text
set AppleScript's text item delimiters to oldTIDS
set forcedErrorText to "application Process \"" & processName & "\"" & linefeed & ¬
tab & "window " & windowName & linefeed & ¬
forcedErrorText
--------------------------------------------------------------------------------
--» OUTPUT
--------------------------------------------------------------------------------
if outputType = "TextEdit" then
outputToTextEdit(forcedErrorText)
else if outputType = "Default Text Editor" then
outputToDefaultTextEditor(forcedErrorText)
end if
--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------
on cngStr:findString intoString:replaceString inString:dataString
set anNSString to current application's NSString's stringWithString:dataString
set dataString to (anNSString's ¬
stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------------------------------
on createDirectoryAtPath:thePath
set {theResult, theError} to current application's NSFileManager's defaultManager()'s createDirectoryAtPath:thePath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
if not (theResult as boolean) then
set errorMsg to theError's localizedDescription() as text
error errorMsg
end if
end createDirectoryAtPath:
--------------------------------------------------------------------------------
# Open in default editor for text files set in the Finder Get-Info window.
--------------------------------------------------------------------------------
on outputToDefaultTextEditor(_text)
set dirPath to POSIX path of (path to temporary items from user domain as text)
set filePath to dirPath & "Window_UI_Exploration.txt"
its createDirectoryAtPath:dirPath
its writeString:_text toPath:filePath
set shCMD to "
open -t " & qf(filePath) of me
do shell script shCMD
end outputToDefaultTextEditor
--------------------------------------------------------------------------------
on ofCount(_text)
set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " of "}
set theCount to length of (text items of _text)
set AppleScript's text item delimiters to oldTIDS
return theCount
end ofCount
--------------------------------------------------------------------------------
on outputToTextEdit(_text)
do shell script "echo " & qf(_text) of me & " | open -f"
end outputToTextEdit
--------------------------------------------------------------------------------
on qf(_text)
return (quoted form of _text)
end qf
--------------------------------------------------------------------------------
on writeString:aString toPath:posixPath
set anNSString to current application's NSString's stringWithString:aString
anNSString's writeToFile:posixPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeString:toPath:
# Other encodings: NSMacOSRomanStringEncoding
--------------------------------------------------------------------------------
Looks like this is a very consistent, repeatable error.
I just confirmed it on another Mac (MBP-15R), also running Keyboard Maestro 7.3.1 (7.3.1) on macOS 10.11.6.
Ahh, good, I was going to suggest temporarily giving Terminal Accessibility permissions. At least that narrows things down (and gets Keyboard Maestro off the hook).
A nuisance that you don’t get the error in Script Debugger.
Can you track down exactly what line is giving you the problem? Add something that fails to the script and keep moving it later until you find the offending command.
Yeah, tomorrow I'll use the tried-and-true divide-and-conquer technique.
I'll add a dialog, or return at mid-point in the script, and then move forward/backwards by 50% until I've nailed it down.
It runs fine here when launched from within KM, SD and SE, but not when launched “from file” via FS or Apple’s Script menulet (-> error -1728). Oddly, it runs fine when launched from file via LaunchBar.
When it runs fine I get for example group 1 as content of the variable tempText (about line 61); when it doesn’t run (-1728) I get «class sgrp» 1 for the tempText variable. So I guess this is some NSString issue (the cngStr function, ~line 126). Just a guess.