Friday, September 20, 2019
  • Index
  •  » Code Exchange
  •  » AST Script Library: A Reluctant Understudy for Applescript Toolbox

#1 2019-04-20 10:19:04 pm

jeromecarney
Member
From:: San Francisco Bay Area
Registered: 2010-10-17
Posts: 3

AST Script Library: A Reluctant Understudy for Applescript Toolbox

Ever since the tragic end announced last October of Bastiaan "DJ Bazzie Wazzie" Boertien's magical sparkly Applescript Toolbox (https://astoolbox.wordpress.com/2018/10 … t-toolbox/), I have stubbornly refused to upgrade any of my Macs to Mojave.  Apple's decision to disallow all 3rd party scripting additions, even when properly signed by known developers, is at best myopic and at worst contemptuous of AS developers.

And with no real compelling reasons to upgrade to Mojave — Dark Mode is fun, but it can in no way compensate for the loss of essential functionality embedded into scores of Applescripts I use every day — I've been very content to continue life at High Sierra ranch this past year.  But now that we're learning more about Marzipan, and the ability to one day hopefully see beloved IOS apps ported for Mac, it was time to begin figuring out a replacement for AST Toolbox, beyond disabling System Integrity Protection.

Below you'll find:

1) My first draft of a script library to replace AST's commands, including 7 of the 20 AST commands I use the most:

   •  AST date with format
   •  AST format date
   •  AST find regex
   •  AST guess language for
   •  AST mouse point location
   •  AST URL decode
   •  AST URL encode

2)Just like AST, all functions were built for fast execution speed.  You'll also note that my implementation of AST find regex is very bare bones, with none of the Toolbox's shiny bells and whistles.

3) Examples demonstrating how the script library's syntax compares to AST's are at the end of this post. I hewed as closely as possible to the original, even throwing in an AST prefix in recognition of Toolbox's legacy, just like the NS prefix in cocoa pays tribute to NeXTSTEP.  I've also included a couple of explanations where necessary, but please see Applescript Toolbox's dictionary for far more helpful and detailed instructions.

4) For a basic primer on script libraries, see https://developer.apple.com/library/arc … aries.html.

Please note:

1) The script library should be saved as "AST.scpt", in your script folder path.

2) Scripts invoking the script library will need to include the following statement in their header, and should also declare a global AST variable:
   set AST to load script  "Macintosh HD:Your Script Folder Path:AST.scpt") as alias
   global AST


3) Due to an insanely busy day job, I won't be able to participate in any active discussions about these functions, or respond to private messages, but I'll try and pop in every few weeks or so.

4) My apologies in advance for any and all errors.  These functions are up and running on my Macs, and I hope they'll run fine on yours, too.

Feel free to suggest corrections / additions, etc. I can only hope DJ Bazzie Wazzie knows how truly wuly thankful I am for all his tremendous efforts.

AST.scpt:

Applescript:


use framework "Foundation"

#AST mouse point location
on ASTmousePointLocation()
   return {item 1 of (current application's NSEvent's mouseLocation() as list), (current application's NSHeight((current application's class "NSScreen"'s mainScreen())'s visibleFrame())) - (item 2 of (current application's NSEvent's mouseLocation() as list))}
end ASTmousePointLocation

#AST guess language for
on ASTguessLanguageFor(theText)
   return (current application's NSLinguisticTagger's dominantLanguageForString:theText) as text
end ASTguessLanguageFor

#AST URL encode
on ASTURLEncode(theText)
   return ((current application's NSString's stringWithString:(theText))'s stringByAddingPercentEscapesUsingEncoding:(current application's NSASCIIStringEncoding)) as text
end ASTURLEncode

#AST URL decode
on ASTURLDecode(theText)
   return ((current application's NSString's stringWithString:(theText))'s stringByReplacingPercentEscapesUsingEncoding:(current application's NSASCIIStringEncoding)) as text
end ASTURLDecode

#AST date with format (Returns date created with the given format. For information on formats, please see http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns)
on ASTDateWithFormat(theFormat, theDate, theLocale)
   set dateFormatter to current application's NSDateFormatter's alloc()'s init()
   set dateFormatter's locale to current application's NSLocale's localeWithLocaleIdentifier:theLocale
   set dateFormatter's dateFormat to theFormat
   set theDate to (dateFormatter's dateFromString:theDate)
   set theDate to theDate as date
   return theDate
end ASTDateWithFormat

#AST format date (Returns string representation of a date in the given format. For information on formats, please see http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns)
on ASTformatDate(theFormat, theDate, theLocale)
   set {theYear, theMonth, theDay, theSeconds} to theDate's {year, month, day, time}
   if theYear < 0 then
       set theYear to -theYear
       set theEra to 0
   else
       set theEra to 1
   end if
   set theCalendar to current application's NSCalendar's currentCalendar()
   set theDate to theCalendar's dateWithEra:theEra |year|:theYear |month|:(theMonth as integer) |day|:theDay hour:0 minute:0 |second|:theSeconds nanosecond:0
   set theFormatter to current application's NSDateFormatter's new()
   theFormatter's setLocale:(current application's NSLocale's localeWithLocaleIdentifier:theLocale)
   theFormatter's setDateFormat:theFormat
   set theString to theFormatter's stringFromDate:theDate
   return theString as text
end ASTformatDate

#AST find regex (Returns a list of regex matches in a string. Variable 'theGroup' is an integer referencing the parts of the matches which correspond to a particular group in the regex. Group 1 references the whole regex, group 2 is the first parenthesised subgroup, and so on, tracking the parenthesis openings from left to right.)
on ASTfindRegex(theRegex, theText, theGroup)
   set theText to current application's NSString's stringWithString:theText #encoding:(current application's NSUTF8StringEncoding)
   set theRegex to current application's NSRegularExpression's regularExpressionWithPattern:(theRegex) options:(current application's NSRegularExpressionAnchorsMatchLines) |error|:(missing value)
   set theFinds to theRegex's matchesInString:theText options:0 range:{0, theText's |length|()}
   set theResults to current application's NSMutableArray's array()
   repeat with aFind in theFinds
       if theGroup is 1 then
           (theResults's addObject:(theText's substringWithRange:(aFind's range())))
       else if theGroup > 1 then
           (theResults's addObject:(theText's substringWithRange:(aFind's rangeAtIndex:(theGroup - 1))))
       end if
   end repeat
   return theResults as list
end ASTfindRegex

Examples:  Applescript Toolbox vs. AST Script Library

Applescript:


#IMPORTANT: BE SURE TO UPDATE THE LINE BELOW WITH YOUR SCRIPT FOLDER PATH
set AST to load script "Macintosh HD:Your Script Folder Path:AST.scpt") as alias

global AST

set {theX1, theY1} to AST mouse point location
tell AST to set {theX2, theY2} to ASTmousePointLocation()

set theLanguage1 to AST guess language for ("eins, zwei, drei, vier")
tell AST to set theLanguage2 to ASTguessLanguageFor("eins, zwei, drei, vier")

set theEncodedText1 to AST URL encode "u / \\ doing & why?"
tell AST to set theEncodedText2 to ASTURLEncode("u / \\ doing & why?")

set theDecodedText1 to AST URL decode "u%20/%20%5C%20do%20&%20why?"
tell AST to set theDecodedText2 to ASTURLDecode("u%20/%20%5C%20do%20&%20why?")

set theRegex1 to AST find regex "(\\d)(\\.)(\\d)" in string "3.4, 3.9 and 4.1" regex group 4
tell AST to set theRegex2 to ASTfindRegex("(\\d)(\\.)(\\d)", "3.4, 3.9 and 4.1", 4)

set theDateString1 to AST format date "EEEE d MMMM yyyy" of date current date using locale "en_US"
tell AST to set theDateString2 to ASTformatDate("EEEE d MMMM yyyy", current date, "en_US")

set theDate1 to AST date with format "EEEE d MMMM yyyy HH:mm" date string "Saturday 20 April 2019 15:30" using locale "en_US"
tell AST to set theDate2 to ASTDateWithFormat("EEEE d MMMM yyyy HH:mm", "Saturday 20 April 2019 15:30", "en_US")

Last edited by jeromecarney (2019-04-21 09:01:42 am)

Offline

 

#2 2019-04-21 02:55:26 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5008

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

Hi. Welcome to MacScripter, Happy Easter, and thanks for posting your library! I'm sure DJ (if he's still around) will be gratified to read your comments about AppleScript Toolbox. I know he put a lot of thought, time, and effort into it.

MacScripter's forum for posting code out of the blue which others may find useful or informative is Code Exchange. If you find this thread disappears from here, don't worry. It will just have been moved to there!

Looking through the library code quickly, I'd point out that NSString's stringByAddingPercentEscapesUsingEncoding: and stringByReplacingPercentEscapesUsingEncoding: methods are deprecated as from macOS 10.12. We're told to use stringByAddingPercentEncodingWithAllowedCharacters: and stringByRemovingPercentEncoding instead. The first allows certain groups of characters not to be escaped, depending on which part of the URL you're encoding. The second doesn't require any parameters. Both methods were introduced with Mac OS 10.9 (Mavericks), which is also when the ability to use library scripts containing ASObjC code was introduced. So no additional version checking's required.

In the examples script, an alternative to using load script would be to put AST.scpt in ~/Library/Script Libraries/ and replace this …

Applescript:

#IMPORTANT: BE SURE TO UPDATE THE LINE BELOW WITH YOUR SCRIPT FOLDER PATH
set AST to load script "Macintosh HD:Your Script Folder Path:AST.scpt") as alias

global AST

… with this at the top of the script:

Applescript:

use AST : script "AST"

The library has to be in place when scripts using it are compiled, but it's apparently reloaded each time they're run, so they don't need to be recompiled whenever the library's updated.


NG

Offline

 

#3 2019-04-21 05:47:56 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5898

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

Nigel Garvey wrote:

I'd point out that NSString's stringByAddingPercentEscapesUsingEncoding: and stringByReplacingPercentEscapesUsingEncoding: methods are deprecated as from macOS 10.12.



Even earlier: 10.11. If anyone's interested in why, the 10.11 release notes have a detailed explanation:

https://developer.apple.com/library/arc … 10_11Notes


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#4 2019-04-21 06:39:16 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5008

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

Shane Stanley wrote:

Even earlier: 10.11.


Ah. Thanks, Shane. I was looking at the Xcode 10.2.1 documentation, which has the earlier methods as being current from 10.0 to 10.11 (but now deprecated). Interestingly (confusingly?) those release notes describe them as NSURL methods, while the Xcode documentation lists all four methods only under NSString.

Last edited by Nigel Garvey (2019-04-21 06:40:36 am)


NG

Offline

 

#5 2019-04-21 06:48:00 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5898

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

It's a bit confusing, but that macOS 10.0-10.11 means introduced in 10.0 and deprecated in 10.11. I suspect it's auto-generated from the header files and the API_DEPRECATED notation. Odd about NSURL instead of NSString.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#6 2019-04-22 02:23:36 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5008

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

jeromecarney wrote:

Applescript:


use framework "Foundation"

#AST mouse point location
on ASTmousePointLocation()
   return {item 1 of (current application's NSEvent's mouseLocation() as list), (current application's NSHeight((current application's class "NSScreen"'s mainScreen())'s visibleFrame())) - (item 2 of (current application's NSEvent's mouseLocation() as list))}
end ASTmousePointLocation

#AST guess language for
on ASTguessLanguageFor(theText)
   return (current application's NSLinguisticTagger's dominantLanguageForString:theText) as text
end ASTguessLanguageFor


Hi jeromecarney.

NSEvent and NSScreen are AppKit classes, so you need a 'use' statement for that framework too.

Your ASTmousePointLocation() handler executes the mouseLocation() method twice, coerces the result to list twice, and makes the mistake of assuming that the items in a record coerced to list will be in a particular order. Also, a screen's visibleFrame() excludes the menu bar and any edge occupied by the Dock. I'd be inclined to base the calculation on the frame() instead, which covers the entire screen area:

Applescript:


use framework "Foundation"
use framework "AppKit"

#AST mouse point location
on ASTmousePointLocation()
   tell (current application's NSEvent's mouseLocation()) to return {its x, (current application's NSHeight((current application's class "NSScreen"'s mainScreen())'s frame())) - (its y)}
end ASTmousePointLocation

According to the Xcode documentation, the dominantLanguageForString: method used in your ASTguessLanguageFor() handler was only introduced in High Sierra, so ideally you should include a comment saying it won't work on earlier systems and/or, better still, include code which returns this information if the library's tried on such. I know it's intended for use on Mojave or later, but it wouldn't hurt to cover the possibility of someone trying to use on an earlier system. I forget what the AppleScript version is in High Sierra. I assume it's 2.6 as Sierra's version was 2.5 and Mojave's is 2.7. You could perhaps add a minimum version to the 'use' statements at the top, although this will stop any of the other handlers being usable either on pre-High Sierra systems:

Applescript:


use AppleScript version "2.6"
use framework "Foundation"
use framework "AppKit"

PS. According to the documentation, a "Natural Language" framework has been introduced in Mojave which includes an NLLanguageRecognizer class which also offers a dominantLanguageForString: method. This may be one to watch in the future. It certainly seems to make better guesses.  wink

Applescript:

use AppleScript version "2.6" -- High Sierra (10.13) or later
use framework "Foundation"

(current application's NSLinguisticTagger's dominantLanguageForString:("Hello")) as text -- "it"

Applescript:

use AppleScript version "2.7" -- Mojave (10.14) or later
use framework "Foundation"
use framework "NaturalLanguage" -- "Natural Language" doesn't compile.

(current application's class "NLLanguageRecognizer"'s dominantLanguageForString:("Hello")) as text -- "en"

Last edited by Nigel Garvey (2019-04-22 03:22:31 am)


NG

Offline

 

#7 2019-04-22 03:14:07 pm

jeromecarney
Member
From:: San Francisco Bay Area
Registered: 2010-10-17
Posts: 3

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

Nigel, Shane:  Thanks for all the very helpful comments and suggestions.

I will be travelling for work for the next couple of weeks, with a pretty extensive schedule, but in early-mid May I'll begin delving into everything, with an eye on updating the code posted in my original post.

Offline

 

#8 2019-04-25 06:58:50 am

DJ Bazzie Wazzie
Member
From:: the Netherlands
Registered: 2004-10-20
Posts: 2809
Website

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

Thank you Jerome!

It's better to use the higher Mac OS X foundation frameworks since they've adopted many features of the lower core frameworks I was using. I like it!

I'll post an link to this topic on my website.

Offline

 

#9 2019-04-25 07:05:01 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5898

Re: AST Script Library: A Reluctant Understudy for Applescript Toolbox

DJ,

One thing you might consider: you could turn your osax into a script library using the same .sdef, or part thereof. You could then either include your code as a framework in the library, or translate it to ASObjC. The only catch to the framework approach is that it wouldn't work in Script Editor.

Just a thought...


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 
  • Index
  •  » Code Exchange
  •  » AST Script Library: A Reluctant Understudy for Applescript Toolbox

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)