Using labeled parameters in a handler to create a unique file name

Lately I have been cleaning up a collection of AppleScriptObjC UI object handlers, and due to many of these having a bunch of options and wanting to make them reasonably robust, I have been getting fond of using labeled parameters. Other than scripting terminology, these don’t seem to be used that much, but since macOS 10.10 Yosemite the built-in labeled handler parameters can also include coercions, provide default values, and be optional. Granted there aren’t that many AppleScript-defined labels to choose from (you need to use at least one for optionals), but you can usually come up with some combination that doesn’t look too goofy.

Also lately there have been some topics here and on StackOverflow about generating a unique file name when moving a file to a folder that may already have an item with that name. This comes up from time to time, and if you are like me, eventually a handler gets tweaked to have a bunch of options - perfect for labeled parameters.

So, since labeled parameters are my new shiny thing, here is a general-purpose handler to create a unique file name that uses them:

on run -- examples -- place a test file on the desktop to see what the copy would be
   set destination to (path to desktop folder) -- POSIX paths can also be used
   set someFileToCopy to (choose file)
   log (getUniqueName out of someFileToCopy for destination) -- just use all defaults
   log (getUniqueName out of "Testing.txt" for destination without fullPath) -- only a name.extension
   log (getUniqueName out of {missing value, ".rtf"} for destination without fullPath) -- not that anyone would do that...
   log (getUniqueName out of someFileToCopy for destination given separatorText:" copy ", startingAt:10) -- different settings
end run

# Get a unique name out of a file name or path for use in a folder - given arguments are optional.
# Note that separatorText should not contain path delimiters {":", "/"}.
to getUniqueName out of anItem as text for aFolder as text given fullPath:fullPath as boolean : true, separator:separator as boolean : true, separatorText:separatorText as text : "_", startingAt:startingAt as integer : 1, minimumDigits:minimumDigits as integer : 1
   try -- get the name and extension (System Events can use both HFS and POSIX paths)
      tell application "System Events" to tell disk item anItem to set {oldName, extension} to {name, name extension}
      if extension is not "" then set extension to "." & extension
      set oldName to text 1 thru -((length of extension) + 1) of oldName -- just the name part
   on error -- not a valid disk item, so treat as a name.extension string
      set here to -(offset of "." in ((reverse of text items of anItem) as text)) - 1 -- last period in the name, if any
      set {oldName, extension} to {text 1 thru here of anItem, ""}
      if here is not -1 then set extension to text (here + 1) thru -1 of anItem
   end try
   if separator is false then set separatorText to "" -- handle with/without
   set counter to item (((startingAt < 1) as integer) + 1) of {startingAt - 1, 0}
   set newName to oldName & extension
   tell application "System Events" to tell (get name of items of folder aFolder whose visible is true)
      repeat while it contains newName -- increase separatorText+counter suffix until unique
         set counter to (counter + 1) as text
         tell minimumDigits to if it > 0 and it > (count counter) then set counter to text -(it) thru -1 of ("000000" & counter)
         set newName to oldName & separatorText & counter & extension
      end repeat
   end tell
   return item ((fullPath as integer) + 1) of {newName, aFolder & newName} -- name or path
end getUniqueName
1 Like