Tuesday, December 12, 2017

#1 2017-10-09 06:07:20 am

daBee
Member
Registered: 2010-02-09
Posts: 81

Dictionary takes FOREVER to load

Hi folks.

I like to have application dictionaries open as a reference when I frustrate myself in AppleScript.  A time-honoured tradition.  The problem now is that I have backup drives, render drives, other drives...all on my Mac Pro box.  I'm thinking it's the culprit in that Script Editor takes several minutes to display the Open Dictionaries... dialog box, then it takes several more to scroll to the application I want, then choose the selected dictionary. 

In the time it takes to open the desired dictionary, I could have completed the script's purpose manually. 

How can I fix this?  Can I restrict the scope of the dictionaries to my startup volume only?

EDITED:  It seems it was polling for scriptable applications through my LAN to my SAN, which would probably take hours to compile items.  That's not good. 

Cheers

Model: Mac Pro
Browser: Safari 603.3.8
Operating System: Mac OS X (10.11.6)

Last edited by daBee (2017-10-09 06:14:36 am)


Filed under: Dictionaries, dialog box

Offline

 

#2 2017-10-09 08:04:27 am

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

Re: Dictionary takes FOREVER to load

I've been using this for years. It only offers the dictionaries of scriptable apps which are already open. It could probably do with a rewrite.  wink

Applescript:

main()

on main()
   tell application "Finder" to set sysv to (system attribute "sysv")
   if (sysv < 4160) then abort("This version of the script only supports Mac OS X 10.4.0 or later.")
   
   -- Nobbled always to open dictionaries in Script Editor, as Script Debugger’s dictionary viewer’s pretty awful and ASObjC Explorer 4 doesn’t have one.
   set editorName to "Script Editor" --getEditorName()
   openDictionaries(editorName)
end main

on getEditorName()
   -- Check that either Script Editor, Smile, or Script Debugger is running.
   tell application "System Events" to set {editorNames, editorFrontmosts} to {name, frontmost} of (every application process whose creator type is "ToyS" or creator type is "VIZF" or creator type is "asDB")
   
   set editorCount to (count editorNames)
   if (editorCount is 0) then
       my abort("Please open (Apple)Script Editor, Smile, or Script Debugger before using this script.")
   else if (editorCount is 1) then
       -- One of the editors is running.
       set editorName to beginning of editorNames
   else if (editorFrontmosts contains true) then
       -- More than one of the editors is running. If one is the frontmost app, use that.
       repeat with i from 1 to editorCount
           if (item i of editorFrontmosts) then
               set editorName to item i of editorNames
               exit repeat
           end if
       end repeat
   else
       -- Otherwise consult the user for which editor to use.
       tell application (path to frontmost application as Unicode text) to set theChoice to (choose from list editorNames with prompt "In which editor do you want to view the dictionaries?" with title "Dictionaries - Running Apps")
       if (theChoice is false) then error number -128
       set editorName to beginning of theChoice
   end if
   
   return editorName
end getEditorName

on abort(msg)
   tell application (path to frontmost application as Unicode text) to display dialog msg buttons {"Cancel"} default button 1 with icon stop cancel button 1 with title "Dictionaries - Running Apps"
end abort

on openDictionaries(editorName)
   set specialNames to {"Finder"}
   
   tell application "System Events" to tell (application processes whose has scripting terminology is true and name is not "Image Capture Scripting") to set {procNames, procFiles} to {its name, its file}
   specialSort(procNames, procFiles, specialNames)
   
   tell application (path to frontmost application as Unicode text) to set theChoice to (choose from list procNames default items specialNames with prompt "Which dictionaries do you want to open?" with title "Dictionaries - Running Apps" with multiple selections allowed)
   if (theChoice is false) then error number -128
   
   set theFiles to {}
   repeat with i from 1 to (count procNames)
       if (item i of procNames is in theChoice) then set end of theFiles to item i of procFiles as alias -- Explicit coercion for OS 10.10, where the 'files' we've obtained are System Events references.
   end repeat
   
   tell application editorName
       activate
       open theFiles
   end tell
end openDictionaries

on specialSort(procNames, procFiles, specialNames)
   -- This script customises the sort to group any "special" application names before the others. It does this by judging non-special names to have higher comparison values.
   script specialsFirst
       property specials : specialNames
       
       on isGreater(a, b)
           set |b's special| to (b is in specials)
           if ((|b's special|) = (a is in specials)) then
               (a > b)
           else
               (|b's special|)
           end if
       end isGreater
   end script
   
   -- This script duplicates in procFiles moves performed in procNames by the custom insertion sort.
   script parallel
       property lst : procFiles
       
       on shift(a, b)
           tell item b of my lst
               repeat with i from b - 1 to a by -1
                   set item (i + 1) of my lst to item i of my lst
               end repeat
               set item a of my lst to it
           end tell
       end shift
   end script
   
   CustomInsertionSort(procNames, 1, -1, {comparer:specialsFirst, slave:parallel})
end specialSort

-- Custom insertion sort from A Dose of Sorts by Nigel Garvey.
on CustomInsertionSort(theList, l, r, customiser)
   script o
       property comparer : me
       property slave : me
       property lst : theList
       
       on isrt(l, r)
           set u to item l of o's lst
           repeat with j from (l + 1) to r
               set v to item j of o's lst
               if (comparer's isGreater(u, v)) then
                   set here to l
                   set item j of o's lst to u
                   repeat with i from (j - 2) to l by -1
                       tell item i of o's lst
                           if (comparer's isGreater(it, v)) then
                               set item (i + 1) of o's lst to it
                           else
                               set here to i + 1
                               exit repeat
                           end if
                       end tell
                   end repeat
                   set item here of o's lst to v
                   slave's shift(here, j)
               else
                   set u to v
               end if
           end repeat
       end isrt
       
       -- Default comparison and slave handlers to customise for an ordinary sort.
       on isGreater(a, b)
           (a > b)
       end isGreater
       
       on shift(a, b)
       end shift
   end script
   
   -- Process the input parmeters.
   set listLen to (count theList)
   if (listLen > 1) then
       -- Negative and/or transposed range indices.
       if (l < 0) then set l to listLen + l + 1
       if (r < 0) then set r to listLen + r + 1
       if (l > r) then set {l, r} to {r, l}
       
       -- Supplied or default customisation scripts.
       if (customiser's class is record) then set {comparer:o's comparer, slave:o's slave} to (customiser & {comparer:o, slave:o})
       
       -- Do the sort.
       o's isrt(l, r)
   end if
   
   return -- nothing.
end CustomInsertionSort


NG

Offline

 

#3 2017-10-10 04:10:10 pm

daBee
Member
Registered: 2010-02-09
Posts: 81

Re: Dictionary takes FOREVER to load

Wow, thanks for that.

I realized there is an actual window for these dictionaries, and I can drop the app onto the Script Editor dock icon and the dictionary comes up.  Works great with Launchbar as well.

Cheers

Offline

 

#4 2017-10-10 06:57:42 pm

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

Re: Dictionary takes FOREVER to load

I wrote:

It could probably do with a rewrite.  wink


Here it is rewritten using ASObjC. It doesn't seem to be any more effective in this form than the original, but it is more — er — modern.  wink

Applescript:

main()

on main()
   script ASObjC
       use AppleScript version "2.4" -- Yosemite (10.10) or later
       use framework "Foundation"
       use framework "AppKit"
       use scripting additions
       
       property specialNames : {"Finder"} -- Any localised application names that should appear already selected at the top of the 'choose from list' dialog.
       property |⌘| : missing value
       property workspace : missing value
       property runningApps : missing value
       
       on main()
           set |⌘| to current application
           set workspace to |⌘|'s class "NSWorkspace"'s sharedWorkspace()
           set runningApps to workspace's runningApplications()
           
           -- Nobbled always to open dictionaries in Script Editor, as Script Debugger’s dictionary viewer’s pretty awful (and has its own "running applications" selector anyway) and ASObjC Explorer 4 doesn’t have one.
           set theEditor to getScriptEditor() -- getEditor()
           openDictionaries(theEditor)
       end main
       
       (* Open Script Editor and return an NSRunningApplication object for it. *)
       on getScriptEditor()
           set SEURL to workspace's URLForApplicationWithBundleIdentifier:("com.apple.ScriptEditor2")
           return workspace's launchApplicationAtURL:(SEURL) options:(0) configuration:(|⌘|'s class "NSDictionary"'s new()) |error|:(missing value)
       end getScriptEditor
       
       (* Return an NSRunningApplication object for the most likely running editor. *)
       on getEditor()
           -- Check that either Script Editor or Script Debugger is running. Smile's bundle identifier can be added to the array if known.
           set editorIDPredicate to |⌘|'s class "NSPredicate"'s predicateWithFormat:("bundleIdentifier IN %@") argumentArray:({{"com.apple.ScriptEditor2", "com.latenightsw.ScriptDebugger6"}})
           set runningEditors to runningApps's filteredArrayUsingPredicate:(editorIDPredicate)
           
           set editorCount to runningEditors's |count|()
           if (editorCount is 0) then
               abort("Please open AppleScript Editor or Script Debugger before using this script.")
           else if (editorCount is 1) then
               -- One of the editors is running.
               set theEditor to runningEditors's firstObject()
           else
               -- More than one of the editors is running. If one currently owns the Menu Bar owner, use it.
               set menuBarOwner to workspace's menuBarOwningApplication()
               if (runningEditors's containsObject:(menuBarOwner)) then
                   set theEditor to menuBarOwner
               else
                   -- Otherwise consult the user for which editor to use.
                   set editorNames to runningEditors's valueForKey:("localizedName")
                   tell application (path to frontmost application as text) to set theChoice to (choose from list (editorNames as list) with prompt "In which editor do you want to view the dictionaries?" with title "Dictionaries - Running Apps")
                   if (theChoice is false) then error number -128
                   set chosenEditorPredicate to |⌘|'s class "NSPredicate"'s predicateWithFormat:("localizedName == %@") argumentArray:(theChoice)
                   set theEditor to (runningEditors's filteredArrayUsingPredicate:(chosenEditorPredicate))'s firstObject()
               end if
           end if
           
           return theEditor
       end getEditor
       
       on abort(msg)
           tell application (path to frontmost application as text) to display dialog msg buttons {"Cancel"} default button 1 with icon stop cancel button 1 with title "Dictionaries - Running Apps"
       end abort
       
       (* Choose and open the required dictionaries. *)
       on openDictionaries(theEditor)
           set runningAppBundleURLs to runningApps's valueForKey:("bundleURL")
           set runningAppNames to runningApps's valueForKey:("localizedName")
           
           -- Preset some stuff for identifying scriptable applications.
           set isScriptableKey to |⌘|'s NSURLApplicationIsScriptableKey
           set isScriptableKeyArray to |⌘|'s class "NSArray"'s arrayWithObject:(isScriptableKey)
           set isScriptableResult to |⌘|'s class "NSDictionary"'s dictionaryWithObject:(true) forKey:(isScriptableKey)
           set specialNames to |⌘|'s class "NSArray"'s arrayWithArray:(specialNames)
           -- Initialise separate arrays in which to collect the names of any "special" scriptable applications and of any others.
           set scriptableAppNames to |⌘|'s class "NSMutableArray"'s new()
           set unspecialScriptableAppNames to |⌘|'s class "NSMutableArray"'s new()
           -- Work through the bundle URLs in turn. If any has a resource value indicating scriptability, add the corresponding localised name to the appropriate array.
           repeat with i from 1 to (count runningAppBundleURLs)
               set thisURL to item i of runningAppBundleURLs
               if (((thisURL's resourceValuesForKeys:(isScriptableKeyArray) |error|:(missing value))'s isEqualToDictionary:(isScriptableResult)) as boolean) then
                   set thisAppName to item i of runningAppNames
                   if ((specialNames's containsObject:(thisAppName)) as boolean) then
                       tell scriptableAppNames to addObject:(thisAppName)
                   else
                       tell unspecialScriptableAppNames to addObject:(thisAppName)
                   end if
               end if
           end repeat
           -- Sort the two collections of names separately, then concatenate them together with the "special" ones in front.
           tell scriptableAppNames to sortUsingSelector:("compare:")
           tell unspecialScriptableAppNames to sortUsingSelector:("compare:")
           tell scriptableAppNames to addObjectsFromArray:(unspecialScriptableAppNames)
           
           -- Ask the user to choose from the found names.
           tell application (path to frontmost application as text) to set theChoice to (choose from list (scriptableAppNames as list) default items (specialNames as list) with prompt "Which dictionaries do you want to open?" with title "Dictionaries - Running Apps" with multiple selections allowed)
           if (theChoice is false) then error number -128
           set theChoice to |⌘|'s class "NSArray"'s arrayWithArray:(theChoice)
           
           -- Open the application files corresponding to the chosen names using the editor passed to this handler.
           set editorPath to theEditor's bundleURL()'s |path|()
           repeat with thisName in theChoice
               set i to (runningAppNames's indexOfObject:(thisName))
               set chosenAppPath to (runningAppBundleURLs's objectAtIndex:(i))'s |path|()
               tell workspace to openFile:(chosenAppPath) withApplication:(editorPath)
           end repeat
       end openDictionaries
   end script
   
   ASObjC's main()
end main


NG

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)