FastScript delays since Snow Leopard
  • Since (I *think*) upgrading to Snow Leopard I sometimes experience delays of a few seconds between hitting a keyboard shortcut and the execution of scripts. When it happens, the FastScripts menu item icon is blue for the duration of the delay, then it goes back to black and the script runs.

    The strange thing is that it doesn't happen all the time. After I invoke a script once, it usually triggers quickly after that first time for a short while.

    I made a screen video:

    http://gallery.me.com/liyanage/100048

    It's a bit hard to see because the menu bar is tiny, but you can see that the icon turns blue when I hit the shortcut, then it stays that way for several seconds, then the script runs (it resizes the window) and the icon turns black.
  • Thanks for the report. I haven't noticed any performance problems on Snow Leopard, and this is the first I've heard of the possibility.

    Is it a script you are running, or an automator action? It's hard to tell but I think I see an action coming up at the end.

    The icon turning blue is where FastScripts is actually yielding control to the script/action/whatever itself. I can't think of what would explain the slowdown except possibly if the script itself is doing something that now takes longer, or if the computer is running low on memory and the script contents have been paged out to disk and need to be read back before running.

    If you can reproduce it on a regular basis, try putting a display dialog message at the beginning of the script. Then you'll know whether the big delay really happens before running, or whether it's sometime in the midst of the script.

    I would also take a look at the system console for any clues of possible misbehavior that could explain the slowdown.

    Daniel
  • Thanks for the hints. I didn't realize that time is already spent in the script when the icon is blue. From a previous discussion (http://www.red-sweater.com/forums/viewtopic.php?id=954) I got the impression that this is something beyond the script author's control. There the problem was that the hang only occurs when the script runs in FastScripts, but not when run in Script Debugger.

    Are you sure this is not the same issue?

    I'll try to figure out where in the script the time is spent with a bunch of logging statements.
  • This is definitely possible that it's similar to the disk eject issue you brought up before. In that case though, I would expect it to be traced down to a specific scripting component (e.g. like you discovered it was disk ejection). I'd be curious to know if some scripting functionality is particularly slow from FastScripts, only starting now in Snow Leopard.
  • I experience this slowdown with Snow Leopard in a major way, with a particular script I use a lot. Incredibly annoying. I don't think it's related to FastScripts, because I have the same issue when I run the script from AppleScript Editor. I haven't gotten any answers yet by Googling, but I've only just started.

    The script is for opening different pref files for the writing app Scrivener; the slowdown seems to happen specifically at the line where the script searches for all pref files matching a specific name fragment:

    set raw_plists to name of every file whose name contains \"literatureandlatte\" and name extension is \"plist\" 


    Anyway, here is the full script, if anyone is curious enough to take a look and give an opinion. I'd be grateful if someone could figure this out. It worked perfectly in Leopard, and was pretty quick, so I have no idea why it would be so slow now - we're talking as much as 10 to 15 seconds.


    (*
    3/21/09
    This script combines what had been 2 separate scripts.
    It allows switching of Preferences profiles for Scrivener, via saved plists.
    Also allows saving new or modified profiles, or deleting ones no longer needed.
    If no named plists are found (in addition to the default Scrivener plist), user is asked if they want to create one.

    Has not been tested extensively but appears to perform same as the 2 separate scripts.

    *)

    property mac_plist_folder : path to preferences
    property operating_plist : POSIX path of (path to preferences) & \"com.literatureandlatte.scrivener.plist\"
    property operating_plist_name : \"com.literatureandlatte.scrivener.plist\"

    property menu_divider : \"- - - - - - - - - - - - - - - - -\"
    property menu_item_for_editing : \"Update, add, or delete profiles\"

    property overwrite_option : \"Overwrite an existing Preferences profile with most recently used plist\"
    property new_option : \"Make a new Preferences profile from current plist\"
    property delete_option : \"Delete a Preferences profile no longer needed\"


    on run
    my check_for_Scrivener()
    set plist_info to my get_current_saved_plists()
    if plist_info is equal to {{}, {}} then
    --if only a default Scrivener profile is found, give user chance to add a named profile
    my help_new_user(plist_info)
    else
    --if named profiles found, ask what user wants to do
    set requested_profile to my get_profile_request(plist_info)
    if requested_profile is equal to menu_divider or requested_profile is equal to menu_item_for_editing then
    --this branch for updating, adding, deleting profiles
    set what_to_do to my get_what_to_do()
    my execute_what_to_do(what_to_do, plist_info)
    else
    --otherwise just switch profiles as user has requested
    my swap_plists(requested_profile, plist_info)
    my start_Scrivener()
    end if
    end if
    end run

    on appIsRunning(appname)
    tell application \"System Events\"
    set processnames to name of every process
    end tell
    if appname is in processnames then
    return true
    else
    return false
    end if
    end appIsRunning

    on check_for_Scrivener()
    if my appIsRunning(\"Scrivener\") then
    display dialog \"Please close Scrivener before running this script!\" buttons {\"OK\"}
    error number -128 -- nice way to quit not just this subroutine but the script
    end if
    end check_for_Scrivener

    on get_current_saved_plists()
    tell application \"Finder\"
    tell folder mac_plist_folder
    set raw_plists to name of every file whose name contains \"literatureandlatte\" and name extension is \"plist\"
    end tell
    end tell
    copy AppleScript's text item delimiters to old_delimiters
    set AppleScript's text item delimiters to \".\"
    set saved_plist_nicknames to {}
    set saved_plist_full_names to {}
    repeat with thisPlist in raw_plists
    if number of text items in thisPlist is equal to 5 then
    copy fourth text item in thisPlist to end of saved_plist_nicknames
    copy thisPlist as string to end of saved_plist_full_names
    end if
    end repeat
    set AppleScript's text item delimiters to old_delimiters
    set plist_info to {saved_plist_nicknames, saved_plist_full_names}
    return plist_info
    end get_current_saved_plists

    -- ====== profile switching subroutines start here ===========================

    on get_profile_request(plist_info)
    set plist_nicknames to item 1 of plist_info
    copy menu_divider to end of plist_nicknames
    copy menu_item_for_editing to end of plist_nicknames
    set profile_selection_list to choose from list plist_nicknames with prompt \"Choose a Scrivener profile to work with\"
    if profile_selection_list is equal to false then
    error number -128 -- nice way to quit not just this subroutine but the script
    end if
    set profile_selection to item 1 of profile_selection_list
    return profile_selection
    end get_profile_request

    on swap_plists(name_of_requested_profile, plist_info)

    set plist_full_names to item 2 of plist_info
    set found to false
    repeat with full_name in plist_full_names
    if name_of_requested_profile is in full_name then
    set profile_name_to_make_operating to full_name as string
    set found to true
    end if
    end repeat
    if found is equal to false then
    display dialog name_of_requested_profile
    display dialog \"Oops - can't find a Scrivener plist to match this name!\"
    error number -128 -- nice way to quit not just this subroutine but the script
    end if

    set switch to false
    tell application \"Finder\"
    tell folder mac_plist_folder
    delete file operating_plist_name
    delay 0.3
    duplicate file profile_name_to_make_operating to path to home folder
    set name of file profile_name_to_make_operating to operating_plist_name
    delay 0.3
    end tell
    set dupe_file to file (((path to home folder) as string) & profile_name_to_make_operating)
    move dupe_file to mac_plist_folder
    end tell
    end swap_plists

    on start_Scrivener()
    tell application \"Scrivener\"
    activate
    end tell
    end start_Scrivener

    -- ====== editing subroutines start here ===========================

    on get_what_to_do()
    set what_to_do to choose from list {overwrite_option, new_option, delete_option} with prompt \"Choose what to do with your Scrivener Preference profiles\"
    if what_to_do is equal to false then
    error number -128 -- nice way to quit not just this subroutine but the script
    else
    return what_to_do
    end if
    end get_what_to_do

    on execute_what_to_do(what_to_do, plist_info)
    if what_to_do as string is equal to overwrite_option then
    my overwrite_profile(plist_info)
    else if what_to_do as string is equal to new_option then
    my make_new_profile(plist_info)
    else if what_to_do as string is equal to delete_option then
    my delete_profile(plist_info)
    end if
    end execute_what_to_do

    on overwrite_profile(plist_info)
    set plist_nicknames to item 1 of plist_info
    set profile_selection_list to choose from list plist_nicknames with prompt \"Choose a Scrivener Preferences profile to overwrite with the most recently used plist\"
    if profile_selection_list is equal to false then
    error number -128 -- nice way to quit not just this subroutine but the script
    end if
    set name_of_requested_profile to item 1 of profile_selection_list
    set plist_full_names to item 2 of plist_info
    set found to false
    repeat with full_name in plist_full_names
    if name_of_requested_profile is in full_name then
    set profile_name_to_overwrite to full_name as string
    set found to true
    end if
    end repeat
    if found is equal to false then
    display dialog name_of_requested_profile
    display dialog \"Oops - can't find a Scrivener plist to match this name!\"
    error number -128 -- nice way to quit not just this subroutine but the script
    end if

    set switch to false
    tell application \"Finder\"
    tell folder mac_plist_folder
    delete file profile_name_to_overwrite
    delay 0.3
    duplicate file operating_plist_name to path to home folder
    set name of file operating_plist_name to profile_name_to_overwrite
    delay 0.3
    end tell
    set dupe_file to file (((path to home folder) as string) & operating_plist_name)
    delay 0.2
    move dupe_file to mac_plist_folder
    end tell
    end overwrite_profile


    on make_new_profile(plist_info)
    set plist_nicknames to item 1 of plist_info
    set nickname_OK to false
    repeat while nickname_OK is equal to false
    set new_nickname to text returned of (display dialog \"Enter a nickname for the new Preferences profile\" default answer \"\" buttons {\"Cancel\", \"OK\"} default button 2)
    if plist_nicknames is equal to {} then
    set nickname_OK to true
    exit repeat
    end if
    repeat with full_name in plist_nicknames
    if new_nickname is not in full_name then
    else
    display dialog \"Sorry, that nickname is taken!\"
    set nickname_OK to false
    exit repeat
    end if
    set nickname_OK to true
    end repeat
    end repeat
    set new_profile_name to \"com.literatureandlatte.scrivener.\" & new_nickname & \".plist\"
    tell application \"Finder\"
    tell folder mac_plist_folder
    duplicate file operating_plist_name to path to home folder
    delay 0.3
    set name of file operating_plist_name to new_profile_name
    delay 0.2
    end tell
    set dupe_file to file (((path to home folder) as string) & operating_plist_name)
    move dupe_file to mac_plist_folder
    end tell
    end make_new_profile

    on delete_profile(plist_info)
    set plist_nicknames to item 1 of plist_info
    set profile_selection_list to choose from list plist_nicknames with prompt \"Choose a Scrivener Preferences profile to delete\"
    if profile_selection_list is equal to false then
    error number -128 -- nice way to quit not just this subroutine but the script
    end if
    set nickname_of_profile_to_delete to item 1 of profile_selection_list
    set plist_full_names to item 2 of plist_info
    set found to false
    repeat with full_name in plist_full_names
    if nickname_of_profile_to_delete is in full_name then
    set profile_to_delete to full_name as string
    set found to true
    end if
    end repeat
    if found is equal to false then
    display dialog name_of_requested_profile
    display dialog \"Oops - can't find a Scrivener plist to match this name!\"
    error number -128 -- nice way to quit not just this subroutine but the script
    end if

    set double_check to button returned of (display dialog \"Are you really sure you want to delete Preferences profile '\" & nickname_of_profile_to_delete & \"'? If you do, the associated plist is going away and ain't coming back!\" buttons {\"Cancel\", \"OK\"} default button 1 with icon caution)
    tell application \"Finder\"
    tell folder mac_plist_folder
    delete file profile_to_delete
    end tell
    end tell

    end delete_profile

    on help_new_user(plist_info)
    set well_gosh_sure to button returned of (display dialog \"Didn't find any plists for Scrivener in ~/Library/Preferences other than the default. If you would like to save the current plist as a new profile, containing the current Preferences for Scrivener, click Yes. Otherwise click No to cancel.\" buttons {\"Yes\", \"No\"} default button 1)
    if well_gosh_sure is equal to \"No\" then
    error number -128 -- nice way to quit not just this subroutine but the script
    else
    my make_new_profile(plist_info)
    end if
    end help_new_user
  • Well, I fixed the script. According to the release notes for changes to Applescript in 10.6, new "security checks" have been introduced when runnning scripts that can potentially slow down Finder routines to a crawl. As usual, the rewritten script is the hideously crude result of trial-by-error, with no actual understanding of what is going on - but it works like a flash, far faster even than the old version, so I'm happy. Here is the rewrite of the offending portion of the routine:


    set raw_plists to {}
    tell application \"Finder\"
    set folder_list to name of every document file of folder mac_plist_folder
    repeat with this_name in folder_list
    if this_name contains \"literatureandlatte\" and this_name ends with \".plist\" then
    copy this_name to end of raw_plists
    end if
    end repeat
    end tell
  • Great! I'm glad to have a clue about how to direct people to resolve these security-induced slowdowns. Thanks for the link and the updated info.

    Daniel
  • Thanks for share this.
Start a New Discussion

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!