youtube link

Good referential text:

Script editor

log "message" can be used to log messages that will be shown in “Messages” accessory pane at the bottom.

File formats

  • Text: save as plain text
  • Script: save as compiled library
  • Application: used to create applet; If in code on open(droppedFiles) ... end open is written, then it becomes a dropplet, which allows drag-n-drop action on the created applet.

Dictionaries

Words inside square bracket are optional arguments. Words on the right of right arrow is what will be returned. What will be returned can be caught by setting it to set variable to. For example,

set myDoc to make new document

Variables

on run
    set theName to "Jill"
    log theName
end run

Scope of variable

By default within current handler, e.g. on run handler, on sub_handler() handler (subroutine). However, if claiming a variable as property at the top of script:

property theName : null

theName will become a global variable.

Data types

  • number (integer or real) set x to 23.25
  • string: set x to "23.25"; but set x to "23.25" as number cast x again to a number
  • date: set x to date "3/5/2023" means set it to 2023-03-05
  • list: set x to {"item1", "item2", "item3"}. The list may comprise of heterogeneous types
  • record (dictionary): set x to {keyA: "valueA", keyB: valueB}

Examples:

set var1 to 22.5
set var2 to 2
set theResult to var1 + var2  # may be +, -, *, /, mod
set var1 to "hello"
set var2 to "world"
set theResult to var1 & space & var2 & "!"  # string concatenation
set var1 to date "12/22/2021"
set var2 to date "12/24/2021"
set theResult to var1 + (2 * days)  # may be days, hours, etc
set theResult to year of var1  # may be year of, month of, day of, etc
set var1 to {"a", 23.9, "c"}
set var2 to item 2 of var1 as string  # get "23.9", indexed from 1
set var1 to {FirstName: "Jon", LastName: "Voight"}
set theResult to FirstName of var1 & space & LastName of var1

# First and Last are reserved words, to use them as keys, surround
# with pipes (`|`), e.g.:
set var1 to {|First|: "Jon", |Last|: "Voight"}
set theResult to |First| of var1 & space |Last| of var2

First script

on run  # explicit on run handler, responding to double clicking
    delay 2  # delay for 2 seconds
    activate  # activate the script
    display dialog "Hello World!"
end run

on open (theFiles)  # on open handler, responding to drag-n-drop
    repeat with aFile in theFiles
        set myText to read file aFiles
        display dialog myText
    end repeat
end open

# to use on idle handler, save it with "Stay open after run handler"
on idle
    activate
    display dialog "Join us soon"
    return 3  # rerun this block 3 seconds later until manualy quit
end idle

Commenting

Block comment:

(*
    Version History
    This is the first build of my script
*)

in line comment: led by -- or #

Repeat loops

on run
    repeat 3 times
    end repeat

    repeat with i from 1 to 3
    end repeat

    set myList to {"Jason", "Joan", "Jack"}
    repeat with anItem in myList
        display dialog "Hello " & anItem as string
    end repeat

    set test to true
    set i to 1
    repeat while test = true
        if i >= 4 then
            set test to false
        end if
        set i tto i + 1
    end repeat
end run

Use exit repeat to break out of repeat earlier.

Conditionals

on run
    set x to 6
    if x = 6 then
        display dialog "x is 6"
    else if x = 5 then
        display dialog "x is 5"
    else
        display dialog "x is neither 5 nor 6"
    end if
end run

Error handling

on run
    try  # ignore quietly errors and break out of try block
        set myDemo to "Hello"
        display dialog myTest
    end try

    try
        display dialog myTest
    on error errName
        display dialog errName
    end try

    try
        if myDemo = "Hello" then
            # this will raise error "message" with errName assigned "message"
            error "message"
            # or phrased as
            # error "message" number -1000
        end if
    on error errName number n
        display dialog errName & return & "with number " & n
    end try
end run

Aias, HFS and POSIX

on run
    set posixPath to "/Users/user/Desktop/name.jpg"

    # converts a POSIX path to an HFS file reference
    set hfsFilePathRef to posix file posixPath

    # converts a POSIX path to an HFS file path
    set hfsFilePath to posix file posixPath as string

    # cannot convert POSIX path to alias directly
    set aliasExample to hfsPath as alias

    # convert an HFS path to a POSIX path
    set backToPosix to posix path of hfsFilePath
end run

Handlers (aka functions)

A handler is a collection of applescript statements that you give a descriptive name.

on run
    set theResult to doMath(8, 2, "+")
    log theResult
end run

on doMath(num1, num2, mathFunc)
    try
	    if mathFunc = "+" then
	        return num1 + num2
	    else if mathFunc = "-" then
	        return num1 - num2
	    else if mathFunc = "*" then
	        return num1 * num2
	    else if mathFunc = "/" then
	        return num1 / num2
	    else
	        error "You must supply a proper math function"
	on error e
	    activate
	    display dialog (e as string) giving up after 8
	end try
end doMath

Note that giving up after N means the dialog will disappear itself if not clicking the dialog button after N seconds.

Within tell application block, be sure to call custom handler with my keyword. For example,

tell application "Numbers"
    set theResult to my doMath(8, 2, "-")
end tell

Quit handler

on run
    set someCondition to false
    if someCondition then
        # tell the script to quit;
		# this will trigger the `on quit` handler if present
        quit
    end if
end run

on quit
    # write cleanup actions your script should run before quitting
    activate
    display dialog "I quit" giving up after 4
    # this will quit current script immediately; without this statement
	# previous `quit` statement will be caught by `on quit` block and
	# quit won't be performed
    continue quit
end quit

Case study: most recent modified file from a folder

on run
    set thePath to "/Users/user/Desktop/folder"
    set newestFile to getNewestFile(thePath)
    return newestFile
end run

on getNewestFile(thePath)
    try
        set posixPath to my convertPathTo(thePath, "POSIX")
        set theFile to do shell script "ls -tp " & quoted form of posixPath & " | grep -Ev '/' | head -n1"
        if theFile is not equal to "" then
            set theFile to posixPath & "/" & theFile
        end if
        return theFile
    on error e
        return ""
    end try
end getNewestFile

on convertPathTo(inputPath, requestedForm)
    try
        set standardPosixPath to POSIX path of inputPath as string
        if requestedForm contains "posix" then
            set transformedPath to POSIX path of standardPosixPath as string
            if transformedPath ends with "/" then
                set transformedPath to character 1 thru -2 of transformedPath as string
            end if
        else if requestedForm contains "alias" then
            set transformedPath to POSIX file (standardPosixPath) as string
            try
                set transformedPath to transformedPath as alias
            on error
                error "The file \"" & transformedPath & "\" doesn't exist and can't be returned as \"alias\""
            end try
        else if requestedForm contains "hfs" then
            set transformedPath to POSIX file (standardPosixPath) as string
        else
            error "Requested path transformation type was an unexpected type"
        end if
        return transformedPath
    on error e
        return false
    end try
end convertPathTo

Case study: automatically scale images

on run
    set filePath to "/Users/user/Desktop/test.png"
    resizeImageWidth(fielPath, 450)
end run

on resizeImageWidth(filePath, pxls)
    try
        do shell script "sips --resampleWidth " & pxls & space & quoted form of filePath
        return true
    on error e
        # TODO do something with the error
        return false
    end try
end resizeImageWidth

Case study: simple hot folder creation

A hot folder is a folder where a script monitor whatever is drag-n-dropped to that folder and perform actions on the object.

on run
    # any startup activities required to run this script can be done here
end run

on idle
    set input to "/Users/user/Desktop/Hot Folder"
    set output to "/Users/user/Desktop/Results"
    set errors to "/Users/user/Desktop/Errors"

    set filePaths to getFiles(input)
    if filePaths is not equal to {} then
        repeat with filePath in filePaths
            if resizeImageWidth(filePath as string, output, 450) then
                removeFile(filePath as string)
            else
                do shell script "mv -f " & quoted form of filePaht & space & quoted form of errors
            end if
        end repeat
    end if
    return 5
end idle

on convertPathTo(inputPath, requestedForm)
    try
        set standardPosixPath to POSIX path of inputPath as string
        if requestedForm contains "posix" then
            set transformedPath to POSIX path of standardPosixPath as string
            if transformedPath ends with "/" then
                set transformedPath to character 1 thru -2 of transformedPath as string
            end if
        else if requestedForm contains "alias" then
            set transformedPath to POSIX file (standardPosixPath) as string
            try
                set transformedPath to transformedPath as alias
            on error
                error "The file \"" & transformedPath & "\" doesn't exist and can't be returned as \"alias\""
            end try
        else if requestedForm contains "hfs" then
            set transformedPath to POSIX file (standardPosixPath) as string
        else
            error "Requested path transformation type was an unexpected type"
        end if
        return transformedPath
    on error e
        return false
    end try
end convertPathTo

on stringToList(inputString, theDelimiter)
    try
        set tid to AppleScript's text item delimters
        set AppleScript's text item delimiters to theDelimiter
        set theList to text items of (inputString as string)
        set AppleScript's text item delimiters to tid
        return theList
    on error e
        set AppleScript's text item delimiters to tid
        return {}
    end try
end stringToList

on resizeImageWidth(filePath, output, pxls)
    try
        do shell script "sips --resampleWidth " & pxls & space & quoted form of filePath & " -o " & qutoed form of output
        return true
    on error e
        return false
    end try
end resizeImageWidth

on getFiles(thePath)
    try
        set posixPath to my convertPathTo(thePath, "posix")
        set theFiles to do shell script "find " & quoted form of posixPath & " -type f ! -name \".*\""
        if theFiles is not equal to "" then
            set fileList to stringToList(theFiles, return)
        end if
        return fileList
    on error e
        # log the error here at some point
        return {}
    end try
end getFiles

on removeFile(theFile)
    try
        set posixPath to convertPathTo(theFile, "posix")
        do shell script "rm -f " & quoted form of posixPath
	    return true
    on error e
        return false
    end try
end removeFile