Skip to content

Instantly share code, notes, and snippets.

@adriannier
Created January 10, 2018 23:37
Show Gist options
  • Save adriannier/a778fc4afb71f16d0ad90297601a815e to your computer and use it in GitHub Desktop.
Save adriannier/a778fc4afb71f16d0ad90297601a815e to your computer and use it in GitHub Desktop.
Processes FileMaker scripts or script steps on the clipboard and displays how many times each variable is used.
(*
AppleScript: Count FileMaker Variables
Processes FileMaker scripts or script steps on the clipboard
and displays how many times each variable is used
-----------------------------------------------------------------------------------
Copyright (c) 2018 by Adrian Nier (http://adriannier.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the
Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------------------
Usage:
1. Select one or many FileMaker scripts or script steps
2. Run this script
Result:
A dialog appears showing how many times any found variable is used in both *Set Variable* steps and as part of calculations.
-----------------------------------------------------------------------------------
*)
on run
displayVariableReport()
end run
on ______________________________________________________REPORTS()
end ______________________________________________________REPORTS
on displayVariableReport()
(*
Displays a dialog with information about the variables found in the currently copied FileMaker script(s) or script step(s).
*)
-- Get script steps from clipboard
set fmXML to fmDataTypesFromClipboardAsXML({"FMScriptSteps", "FMScripts"})
if fmXML is "" then return
-- Protect global variables
set fmXML to snr(fmXML, "$$", "<GLOBALVAR>")
-- Get local variable names
set allVariableNames to wordsStartingWith(fmXML, "$")
set uniqueVariableNames to uniqueWordsStartingWith(fmXML, "$")
-- Restore global variables
set fmXML to snr(fmXML, "<GLOBALVAR>", "$$")
-- Get global variable names
set allVariableNames to allVariableNames & wordsStartingWith(fmXML, "$$")
set uniqueVariableNames to uniqueWordsStartingWith(fmXML, "$$") & uniqueVariableNames
-- Initialize loop variables
set varInfos to {}
set singleUseVariableFound to false
repeat with varName in uniqueVariableNames
set varUseCount to countMatchesInList(varName as text, allVariableNames)
if varUseCount = 1 then
-- Found variable used only once
set singleUseVariableFound to true
end if
if (varUseCount < 10) then
set varUseCount to " " & (varUseCount as text)
else if (varUseCount < 100) then
set varUseCount to " " & (varUseCount as text)
else if (varUseCount < 1000) then
set varUseCount to " " & (varUseCount as text)
end if
set end of varInfos to (varUseCount as text) & "× " & (varName as text)
end repeat
-- Sort variable information
set varInfos to sortList(varInfos)
-- Convert variable information to text
set varInfo to listToText(varInfos, ASCII character 10)
-- Display dialog
activate
if uniqueVariableNames is {} then
display alert "No variables found" message "The copied scripts or script steps use no variables." as critical
else if singleUseVariableFound then
display alert "Found variables only used once" message varInfo as critical
else
display alert "All variables are used at least twice" message varInfo
end if
end displayVariableReport
on ________________________________________OUTPUT_IN_TEXTEDIT()
end ________________________________________OUTPUT_IN_TEXTEDIT
on outputClipboardInTextEdit()
(*
Outputs the current clipboard in TextEdit.
*)
try
set xmlSource to fmDataTypesFromClipboardAsFormattedXML(false)
outputXMLInTextEdit(xmlSource, "FMClipboard")
on error eMsg number eNum
error "outputClipboardInTextEdit: " & eMsg number eNum
end try
end outputClipboardInTextEdit
on outputXMLInTextEdit(xmlSource, outputName)
(*
Outputs the XML in TextEdit using a temporary file with the specified name.
*)
try
-- Get FileMaker data type
set fmDataType to fmDataTypeOfXML(xmlSource)
if fmDataType is "FMInvalidDataType" then return
-- Make sure a valid output name is set
if outputName is false then
set outputName to fmDataType
end if
-- Add suffix to document name if necessary
if outputName does not end with ".xml" then
set documentName to outputName & ".xml"
else
set documentName to outputName
end if
-- Is the document open in TextEdit?
tell application "TextEdit"
set documentExists to (exists document documentName)
end tell
if documentExists then
-- Close document if necessary
tell application "TextEdit" to close document documentName
end if
-- Generate file path
set filePath to temporaryPathWithNameAndSuffix(outputName, ".xml")
-- Write XML to file
writeToFileAtPath(xmlSource, filePath)
-- Open file with TextEdit
do shell script "open -a /Applications/TextEdit.app " & qpp(filePath)
on error eMsg number eNum
error "outputXMLInTextEdit: " & eMsg number eNum
end try
end outputXMLInTextEdit
on __________________________________CLIPBOARD_MANIPULATION()
end __________________________________CLIPBOARD_MANIPULATION
on xmlFileToClipboard(filePath)
(*
Puts the contents of the specified XML file to the clipboard for usage in FileMaker.
*)
try
-- Convert file path to HFS path
set filePath to anyPathToHFSPath(filePath)
-- Get the XML from the file
set xmlSource to readFile(filePath)
-- Clean up XML
set xmlSource to trim(xmlSource)
-- Get FileMaker data type
set fmDataType to fmDataTypeOfXML(xmlSource)
-- Read as appropriate data
if fmDataType is "FMLayoutObjects" then
set xmlData to readFileAsClass(filePath, «class XML2»)
else if fmDataType is "FMScripts" then
set xmlData to readFileAsClass(filePath, «class XMSC»)
else if fmDataType is "FMScriptSteps" then
set xmlData to readFileAsClass(filePath, «class XMSS»)
else if fmDataType is "FMTables" then
set xmlData to readFileAsClass(filePath, «class XMTB»)
else if fmDataType is "FMFields" then
set xmlData to readFileAsClass(filePath, «class XMFD»)
else if fmDataType is "FMCustomFunctions" then
set xmlData to readFileAsClass(filePath, «class XMFN»)
else
error "Invalid data type."
end if
-- Set the clipboard
set the clipboard to xmlData
on error eMsg number eNum
error "xmlFileToClipboard: " & eMsg number eNum
end try
end xmlFileToClipboard
on xmlToClipboard(xmlSource)
(*
Puts the specified XML to the clipboard for usage in FileMaker.
*)
try
-- Clean up XML
set xmlSource to trim(xmlSource)
-- Get FileMaker data type
set fmDataType to fmDataTypeOfXML(xmlSource)
-- Write XML data to temporary file
set tempFilePath to writeToTemporaryFileWithNameAndSuffix(xmlSource, false, ".xml")
-- Read as appropriate data
if fmDataType is "FMLayoutObjects" then
set xmlData to readFileAsClass(tempFilePath, «class XML2»)
else if fmDataType is "FMScripts" then
set xmlData to readFileAsClass(tempFilePath, «class XMSC»)
else if fmDataType is "FMScriptSteps" then
set xmlData to readFileAsClass(tempFilePath, «class XMSS»)
else if fmDataType is "FMTables" then
set xmlData to readFileAsClass(tempFilePath, «class XMTB»)
else if fmDataType is "FMFields" then
set xmlData to readFileAsClass(tempFilePath, «class XMFD»)
else if fmDataType is "FMCustomFunctions" then
set xmlData to readFileAsClass(tempFilePath, «class XMFN»)
else
error "Invalid data type."
end if
-- Delete temporary file
deleteFile(tempFilePath)
-- Set the clipboard
set the clipboard to xmlData
on error eMsg number eNum
try
-- Delete temporary file
deleteFile(tempFilePath)
end try
error "FMClipboardHelper/xmlToClipboard(): " & eMsg number eNum
end try
end xmlToClipboard
on __________________________________________CLIPBOARD_TO_FILE()
end __________________________________________CLIPBOARD_TO_FILE
on fmDataTypeFromClipboardAsFileWithName(fmDataType, fileName)
(*
Stores the XML data of the specified type found on the clipboard to a temporary file with the specified name.
*)
return fmDataTypesFromClipboardAsFileWithName({fmDataType}, fileName)
end fmDataTypeFromClipboardAsFileWithName
on fmDataTypesFromClipboardAsFileWithName(fmDataTypes, fileName)
(*
Stores the XML data of one of the specified types found on the clipboard to a temporary file with the specified name.
*)
return fmDataTypesFromClipboardAsFileWithNameInDirectory(fmDataTypes, fileName, false)
end fmDataTypesFromClipboardAsFileWithName
on fmDataTypeFromClipboardAsFileWithNameInDirectory(fmDataType, fileName, folderPath)
(*
Stores the XML data of the specified type found on the clipboard to a file with the specified name in the specified directory.
*)
return fmDataTypesFromClipboardAsFileWithNameInDirectory({fmDataType}, fileName, folderPath)
end fmDataTypeFromClipboardAsFileWithNameInDirectory
on fmDataTypesFromClipboardAsFileWithNameInDirectory(fmDataTypes, fileName, folderPath)
(*
Stores the XML data of one of the specified types found on the clipboard to a file with the specified name in the specified directory.
*)
try
-- Get the XML data from clipboard
try
set fmData to fmDataTypesFromClipboard(fmDataTypes)
on error eMsg number eNum
if eNum is 1000 then return ""
error eMsg number eNum
end try
-- Check file name
if fileName is false then
set fileName to fmDataTypeOfClipboard()
end if
if folderPath is false then
-- Create file in user's temporary items folder
set tempFilePath to writeToTemporaryFileWithNameAndSuffix(fmData, fileName, ".xml")
-- Format XML file
formatXMLAtPath(tempFilePath)
return tempFilePath
else
-- Convert folder path to HFS path
set folderPath to anyPathToHFSPath(folderPath)
-- Make sure the folder path ends with a colon
if folderPath does not end with ":" then
set folderPath to folderPath & ":"
end if
-- Generate file path
set filePath to folderPath & fileName & ".xml"
writeToFileAtPath(fmData, filePath)
-- Format XML file
formatXMLAtPath(filePath)
return filePath
end if
on error eMsg number eNum
error "fmDataTypesFromClipboardAsFileWithNameInDirectory: " & eMsg number eNum
end try
end fmDataTypesFromClipboardAsFileWithNameInDirectory
on __________________________________________CLIPBOARD_TO_XML()
end __________________________________________CLIPBOARD_TO_XML
on clipboardAsXML()
(*
Returns the XML found on the clipboard as text.
*)
return fmDataTypesFromClipboardAsXML(false)
end clipboardAsXML
on fmDataTypeFromClipboardAsXML(fmDataType)
(*
Returns the XML of the specified type found on the clipboard as text.
*)
return fmDataTypesFromClipboardAsXML({fmDataType})
end fmDataTypeFromClipboardAsXML
on fmDataTypesFromClipboardAsXML(fmDataTypes)
(*
Returns the XML of one of the specified types found on the clipboard as text.
*)
try
-- Get the XML data from clipboard
try
set fmData to fmDataTypesFromClipboard(fmDataTypes)
on error eMsg number eNum
if eNum is 1000 then return ""
error eMsg number eNum
end try
set fmDataType to fmDataTypeOfClipboard()
set tempFilePath to writeToTemporaryFileWithNameAndSuffix(fmData, fmDataType, ".xml")
set fmXML to readFile(tempFilePath)
deleteFile(tempFilePath)
return fmXML
on error eMsg number eNum
error "fmDataTypesFromClipboardAsXML: " & eMsg number eNum
end try
end fmDataTypesFromClipboardAsXML
on ____________________________CLIPBOARD_TO_FORMATTED_XML()
end ____________________________CLIPBOARD_TO_FORMATTED_XML
on fmDataTypeFromClipboardAsFormattedXML(fmDataType)
(*
Returns the XML of the specified type found on the clipboard as formatted text.
*)
return fmDataTypesFromClipboardAsFormattedXML({fmDataType})
end fmDataTypeFromClipboardAsFormattedXML
on fmDataTypesFromClipboardAsFormattedXML(fmDataTypes)
(*
Returns the XML of one of the specified types found on the clipboard as formatted text.
*)
try
-- Get the XML data from clipboard
try
set fmData to fmDataTypesFromClipboard(fmDataTypes)
on error eMsg number eNum
if eNum is 1000 then return ""
error eMsg number eNum
end try
set fmDataType to fmDataTypeOfClipboard()
set tempFilePath to writeToTemporaryFileWithNameAndSuffix(fmData, fmDataType, ".xml")
formatXMLAtPath(tempFilePath)
set fmXML to readFile(tempFilePath)
deleteFile(tempFilePath)
return fmXML
on error eMsg number eNum
error "fmDataTypesFromClipboardAsFormattedXML: " & eMsg number eNum
end try
end fmDataTypesFromClipboardAsFormattedXML
on _________________________________________CLIPBOARD_TO_DATA()
end _________________________________________CLIPBOARD_TO_DATA
on fmDataTypesFromClipboard(fmDataTypes)
(*
Returns the XML of one of the specified types found on the clipboard as data.
*)
try
if fmDataTypes is false then
set fmDataTypes to {"FMLayoutObjects", "FMScripts", "FMScriptSteps", "FMTables", "FMFields", "FMCustomFunctions"} -- return anyDataTypesFromClipboard()
end if
set clipboardContents to the clipboard
try
repeat with i from 1 to count of fmDataTypes
set fmDataType to item i of fmDataTypes
if fmDataType is "FMLayoutObjects" then
try
return «class XML2» of clipboardContents
end try
else if fmDataType is "FMScripts" then
try
return «class XMSC» of clipboardContents
end try
else if fmDataType is "FMScriptSteps" then
try
return «class XMSS» of clipboardContents
end try
else if fmDataType is "FMTables" then
try
return «class XMTB» of clipboardContents
end try
else if fmDataType is "FMFields" then
try
return «class XMFD» of clipboardContents
end try
else if fmDataType is "FMCustomFunctions" then
try
return «class XMFN» of clipboardContents
end try
else
error "Unknown data type. Available data types are: FMLayoutObjects, FMScripts, FMScriptSteps, FMTables, FMFields, and FMCustomFunctions"
end if
end repeat
error "No data type found."
on error eMsg number eNum
set fmDataType to listToText(fmDataTypes, ", ")
set dataTypesDescriptions to descriptionsForFMDataTypes(fmDataTypes)
set actualFMDataType to fmDataTypeOfClipboard()
set actualDataTypeDescription to descriptionForFMDataType(actualFMDataType)
if (count of fmDataTypes) is 1 then
set thisObjectString to "the correct objects"
else
set thisObjectString to "any of these objects"
end if
if actualFMDataType is "FMInvalidClipboard" then
-- Anything other than a record is on the clipboard
if fmDataType is "FMLayoutObjects" then
-- Layout objects were requested
set eMsg to "Could not get " & listToText(dataTypesDescriptions, " or ") & " from clipboard. Please make sure to actually copy " & thisObjectString & " to the clipboard. This error usually occurs when the copy command is performed while the Inspector panel is the frontmost window."
else
-- Anything other than layout objects were requested
set eMsg to "Could not get " & listToText(dataTypesDescriptions, " or ") & " from clipboard. Please make sure to actually copy " & thisObjectString & " to the clipboard."
end if
else if actualFMDataType is "FMInvalidDataType" then
-- An unknown data type was found on the clipboard
set eMsg to "Could not get " & listToText(dataTypesDescriptions, " or ") & " from clipboard. What was copied is not supported by this script."
else
-- The wrong data type was found on the clipboard
set eMsg to "The clipboard contains " & actualDataTypeDescription & " not " & listToText(dataTypesDescriptions, " or ") & "."
end if
activate
display alert "Clipboard Error" message eMsg as critical
error eMsg number 1000
end try
on error eMsg number eNum
error "fmDataTypesFromClipboard: " & eMsg number eNum
end try
end fmDataTypesFromClipboard
on anyDataTypesFromClipboard()
(*
Returns the XML found on the clipboard as data.
*)
try
set fmDataType to fmDataTypeOfClipboard()
set clipboardContents to the clipboard
if fmDataType is "FMLayoutObjects" then
return «class XML2» of clipboardContents
else if fmDataType is "FMScripts" then
return «class XMSC» of clipboardContents
else if fmDataType is "FMScriptSteps" then
return «class XMSS» of clipboardContents
else if fmDataType is "FMTables" then
return «class XMTB» of clipboardContents
else if fmDataType is "FMFields" then
return «class XMFD» of clipboardContents
else if fmDataType is "FMCustomFunctions" then
return «class XMFN» of clipboardContents
else
error "Unknown data type. Available data types are: FMLayoutObjects, FMScripts, FMScriptSteps, FMTables, FMFields, and FMCustomFunctions"
end if
on error eMsg number eNum
error "anyDataTypesFromClipboard: " & eMsg number eNum
end try
end anyDataTypesFromClipboard
on __________________________________________________DATA_TYPES()
end __________________________________________________DATA_TYPES
on fmDataTypeOfClipboard()
(*
Returns the data type of the current clipboard.
*)
set clipboardContents to the clipboard
set clipboardClass to (class of clipboardContents) as text
if clipboardClass is not "record" then
-- The data on the clipboard has the wrong class
return "FMInvalidClipboard"
else
try
-- The following line produces a text representation of the record as error message
get item 0 of clipboardContents
on error eMsg
-- Parse the error message to get the data class
set o to offset of "«class " in eMsg
if o is 0 then
-- The text "«class " was not found
return "FMInvalidClipboard"
end if
-- Get a substring from the error message representing the class name
set fmDataClassName to text (o + 7) thru (o + 10) of eMsg
-- Convert class name to data type
set fmDataType to fmDataClassNameToDataType(fmDataClassName)
return fmDataType
end try
end if
end fmDataTypeOfClipboard
on fmDataTypeOfXML(xmlSource)
try
set prvDlmt to text item delimiters
try
set text item delimiters to "<fmxmlsnippet"
set tempString to text item 2 of xmlSource
set text item delimiters to "<"
set tempString to text item 2 of tempString
set o1 to offset of ">" in tempString
set o2 to offset of " " in tempString
if o1 < o2 then
set text item delimiters to ">"
else
set text item delimiters to " "
end if
set dataType to text item 1 of tempString
on error
set dataType to false
end try
set text item delimiters to prvDlmt
if dataType is "Layout" then
return "FMLayoutObjects"
else if dataType is "Script" then
return "FMScripts"
else if dataType is "Step" then
return "FMScriptSteps"
else if dataType is "BaseTable" then
return "FMTables"
else if dataType is "Field" then
return "FMFields"
else if dataType is "CustomFunction" then
return "FMCustomFunctions"
else
return "FMInvalidDataType"
end if
on error eMsg number eNum
error "fmDataTypeOfXML: " & eMsg number eNum
end try
end fmDataTypeOfXML
on fmDataClassNameToDataType(fmDataClassName)
(*
Converts a data class name to its data type.
*)
if fmDataClassName is "XML2" then
return "FMLayoutObjects"
else if fmDataClassName is "XMSC" then
return "FMScripts"
else if fmDataClassName is "XMSS" then
return "FMScriptSteps"
else if fmDataClassName is "XMTB" then
return "FMTables"
else if fmDataClassName is "XMFD" then
return "FMFields"
else if fmDataClassName is "XMFN" then
return "FMCustomFunctions"
else
return "FMInvalidDataType"
end if
end fmDataClassNameToDataType
on descriptionsForFMDataTypes(fmDataTypes)
(*
Returns a list of descriptions for the specified data types.
*)
set theDescriptions to {}
repeat with i from 1 to count of fmDataTypes
set end of theDescriptions to descriptionForFMDataType(item i of fmDataTypes)
end repeat
return theDescriptions
end descriptionsForFMDataTypes
on descriptionForFMDataType(fmDataType)
(*
Returns a description for the specified data type.
*)
if fmDataType is "FMLayoutObjects" then
return "layout objects"
else if fmDataType is "FMScripts" then
return "scripts"
else if fmDataType is "FMScriptSteps" then
return "script steps"
else if fmDataType is "FMTables" then
return "tables"
else if fmDataType is "FMFields" then
return "fields"
else if fmDataType is "FMCustomFunctions" then
return "custom functions"
else
return "unknown type"
end if
end descriptionForFMDataType
on _________________________________________________FILE_SYSTEM()
end _________________________________________________FILE_SYSTEM
on writeToTemporaryFileWithNameAndSuffix(content, fileName, theSuffix)
(*
Writes content to a file with the specified name and suffix to the user's temporary items folder.
*)
try
-- Generate temporary file path
set tempFilePath to temporaryUniquePathWithNameAndSuffix(fileName, theSuffix)
-- Write to temporary file
writeToFileAtPath(content, tempFilePath)
return tempFilePath
on error eMsg number eNum
error "writeToTemporaryFileWithNameAndSuffix: " & eMsg number eNum
end try
end writeToTemporaryFileWithNameAndSuffix
on writeToFileAtPath(content, filePath)
(*
Writes content to the file at the specified path.
*)
try
-- Convert file path to HFS path
set filePath to anyPathToHFSPath(filePath)
-- Open file
try
open for access file filePath with write permission
on error eMsg number eNum
error "Could not open file with write permission: " & eMsg number eNum
end try
-- Write to file
try
set fileEnd to 0
set eof of file filePath to fileEnd
set writeData to content
try
write writeData to file filePath starting at fileEnd as «class utf8»
on error
write writeData to file filePath starting at fileEnd
end try
on error eMsg number eNum
try
close access file filePath
end try
error "Error while writing to file: " & eMsg number eNum
end try
-- Close file
try
close access file filePath
end try
return true
on error eMsg number eNum
error "writeToFileAtPath: " & eMsg number eNum
end try
end writeToFileAtPath
on readFile(filePath)
(*
Returns the contents of a file as UTF-8 text.
*)
try
readFileAsClass(filePath, «class utf8»)
on error eMsg number eNum
error "readFile: " & eMsg number eNum
end try
end readFile
on readFileAsClass(filePath, contentClass)
(*
Returns the contents of a file as the specified class.
*)
try
-- Convert file path to HFS path
set filePath to anyPathToHFSPath(filePath)
-- Open file for reading
try
open for access file filePath
on error eMsg number eNum
error "Could not open file: " & eMsg number eNum
end try
-- Read
try
set fileContents to read file filePath as contentClass
on error eMsg number eNum
try
close access file filePath
end try
error "Error while trying to read file: " & eMsg number eNum
end try
-- Close
try
close access file filePath
end try
return fileContents
on error eMsg number eNum
set eMsg to "readFile: " & eMsg
error eMsg number eNum
end try
end readFileAsClass
on deleteFile(filePath)
(*
Deletes the file at the specified path.
*)
try
if existsFile(filePath) is false then return
tell application "System Events"
delete file filePath
end tell
on error eMsg number eNum
do shell script "/bin/rm -f " & qpp(filePath)
end try
end deleteFile
on existsFile(filePath)
(*
Checks if a file at the specified path exists.
*)
try
-- Convert file path to HFS path
set filePath to anyPathToHFSPath(filePath)
tell application "System Events" to return (exists file filePath)
on error eMsg number eNum
error "existsFile: " & eMsg number eNum
end try
end existsFile
on makeDirectory(parentPath, directoryName)
(*
Creates a folder with the specified name in a folder at the specified path.
*)
try
-- Convert parent path to HFS path
set parentPath to anyPathToHFSPath(parentPath)
if parentPath does not end with ":" then
set parentPath to parentPath & ":"
end if
-- Generate full directory path
set directoryPath to parentPath & directoryName & ":"
tell application "System Events"
if (exists folder directoryPath) is false then
-- Directory does not exist; create it
make new folder at the end of folders of folder parentPath with properties {name:directoryName}
end if
end tell
return directoryPath
on error eMsg number eNum
error "makeDirectory: " & eMsg number eNum
end try
end makeDirectory
on temporaryPathWithNameAndSuffix(fileName, theSuffix)
(*
Creates a temporary file path with the specified name and suffix.
*)
try
-- Add dot to suffix
if character 1 of theSuffix is not "." then
set theSuffix to "." & theSuffix
end if
-- Get the path to the temporary items folder
set tempItemsDirectoryPath to (path to temporary items folder from user domain) as text
-- Make sure the clipboard helper's directory exists
set parentFolderPath to makeDirectory(tempItemsDirectoryPath, "FMClipboardHelper")
return parentFolderPath & fileName & theSuffix
on error eMsg number eNum
error "temporaryPathWithNameAndSuffix: " & eMsg number eNum
end try
end temporaryPathWithNameAndSuffix
on temporaryUniquePathWithNameAndSuffix(fileName, theSuffix)
(*
Creates a temporary unique file path. Uses fileName as base name if not set to false. Uses theSuffix as suffix if not set to false.
*)
try
if fileName is false then
-- No file name specified; generate one
-- Generate pseudorandom numbers
set rand1 to (round (random number from 100 to 999)) as text
set rand2 to (round (random number from 100 to 999)) as text
set rand3 to (round (random number from 100 to 999)) as text
set randomText to rand1 & "-" & rand2 & "-" & rand3
-- Generate full file name
set fileName to (("AppleScriptTempFile_" & randomText) as text)
end if
if theSuffix is not false then
-- Add dot to suffix
if character 1 of theSuffix is not "." then
set theSuffix to "." & theSuffix
end if
else
set theSuffix to ""
end if
-- Get the path to the temporary items folder
set tempItemsDirectoryPath to (path to temporary items folder from user domain) as text
-- Make sure the clipboard helper's directory exists
set parentFolderPath to makeDirectory(tempItemsDirectoryPath, "FMClipboardHelper")
-- Make sure the file does not exist
set rNumber to 1
repeat
if rNumber is 1 then
set tempFilePath to parentFolderPath & fileName & theSuffix
else
set tempFilePath to parentFolderPath & fileName & "_" & (rNumber as text) & theSuffix
end if
tell application "System Events"
if (exists file tempFilePath) is false then
exit repeat
end if
end tell
set rNumber to rNumber + 1
end repeat
return tempFilePath
on error eMsg number eNum
error "temporaryUniquePathWithNameAndSuffix: " & eMsg number eNum
end try
end temporaryUniquePathWithNameAndSuffix
on qpp(aPath)
(*
Returns a quoted posix path of the item at the specified path.
*)
return quoted form of (POSIX path of anyPathToHFSPath(aPath))
end qpp
on anyPathToHFSPath(aPath)
(*
Converts any path to a HFS path.
*)
try
-- Expand tilde in path
if aPath starts with "~" then
-- Get the path to the user’s home folder
set userPath to POSIX path of (path to home folder)
-- Remove trailing slash
if userPath ends with "/" then set userPath to text 1 thru -2 of userPath as text
if aPath is "~" then
set aPath to userPath
else
set aPath to userPath & text 2 thru -1 of aPath as text
end if
end if
-- Convert to HFS style path if necessary
if aPath does not contain ":" then set aPath to (POSIX file aPath) as text
return aPath
on error eMsg number eNum
error "anyPathToHFSPath: " & eMsg number eNum
end try
end anyPathToHFSPath
on ________________________________________________________TEXT()
end ________________________________________________________TEXT
on formatXMLAtPath(filePath)
(*
Formats an XML file in place at the specified path.
*)
try
do shell script "/usr/bin/xmllint --format --output " & qpp(filePath) & " " & qpp(filePath)
on error eMsg number eNum
error "formatXMLAtPath: " & eMsg number eNum
end try
end formatXMLAtPath
on snr(aText, aPattern, aReplacement)
(*
Searches and replaces a pattern in the specified text.
*)
try
if (class of aPattern) is list and (class of aReplacement) is list then
if (count of aPattern) is not (count of aReplacement) then error "The count of patterns and replacements needs to match."
-- Process matching list of patterns and replacements
repeat with i from 1 to count of aPattern
set aText to snr(aText, item i of aPattern, item i of aReplacement)
end repeat
return aText
else if class of aPattern is list then
-- Replace multiple patterns with the same text
repeat with i from 1 to count of aPattern
set aText to snr(aText, item i of aPattern, aReplacement)
end repeat
return aText
end if
-- Return text early if it doesn't contain the pattern
if aText does not contain aPattern then return aText
set prvDlmt to text item delimiters
try
set text item delimiters to aPattern
set tempList to text items of aText
set text item delimiters to aReplacement
set aText to tempList as text
end try
set text item delimiters to prvDlmt
return aText
on error eMsg number eNum
error "snr: " & eMsg number eNum
end try
end snr
on textToList(aString, aDelimiter)
(*
Converts a text to list using the specified delimiter.
*)
try
set prvDlmt to text item delimiters
set text item delimiters to aDelimiter
set aList to text items of aString
set text item delimiters to prvDlmt
return aList
on error eMsg number eNum
error "textToList: " & eMsg number eNum
end try
end textToList
on listToText(aList, aDelimiter)
(*
Converts a list to a text using the specified delimiter.
*)
try
set prvDlmt to text item delimiters
set text item delimiters to aDelimiter
set aString to aList as text
set text item delimiters to prvDlmt
return aString
on error eMsg number eNum
error "listToText: " & eMsg number eNum
end try
end listToText
on sortList(aList)
(*
Sorts a list of strings.
*)
try
set aText to listToText(aList, ASCII character 10)
return paragraphs of (do shell script "/bin/echo " & quoted form of aText & " | /usr/bin/sort")
on error eMsg number eNum
error "sortList: " & eMsg number eNum
end try
end sortList
on countMatchesInList(aString, aList)
(*
Counts the matches of a string in a list.
*)
try
set matchCount to 0
repeat with i from 1 to count of aList
if item i of aList is aString then
set matchCount to matchCount + 1
end if
end repeat
return matchCount
on error eMsg number eNum
error "uniqueWordsStartingWith: " & eMsg number eNum
end try
end countMatchesInList
on uniqueWordsStartingWith(aText, aPrefix)
(*
Finds all words that start with a prefix in a text. Returns only the first occurrence of each word.
*)
try
set wordList to textToList(aText, aPrefix)
if (count of wordList) is 1 then return {}
set uniqueWords to {}
repeat with i from 2 to count of wordList
set thisWord to aPrefix & first word of item i of wordList
if thisWord is not in uniqueWords then
set end of uniqueWords to thisWord
end if
end repeat
set uniqueWords to sortList(uniqueWords)
return uniqueWords
on error eMsg number eNum
error "uniqueWordsStartingWith: " & eMsg number eNum
end try
end uniqueWordsStartingWith
on wordsStartingWith(aText, aPrefix)
(*
Finds all words that start with a prefix in a text.
*)
try
set wordList to textToList(aText, aPrefix)
if (count of wordList) is 1 then return {}
set allWords to {}
repeat with i from 2 to count of wordList
set thisWord to aPrefix & first word of item i of wordList
set end of allWords to thisWord
end repeat
set allWords to sortList(allWords)
return allWords
on error eMsg number eNum
error "wordsStartingWith: " & eMsg number eNum
end try
end wordsStartingWith
on trim(aText)
(*
Strips a text of its surrounding white space.
*)
try
(* Strip leading white space *)
if aText is "" then return aText
-- Initialize the collector variable
set leadingWhiteSpace to ""
repeat with i from 1 to count of characters in aText
-- Is this character still whitespace?
if (ASCII number (character i of aText)) > 32 and (ASCII number (character i of aText)) ≠ 202 then
exit repeat -- No more white space; stop collecting it
else
-- Collect white space
set leadingWhiteSpace to leadingWhiteSpace & character i of aText
end if
end repeat
-- Mark the beginning of the text
set aText to "#!#BEGINNING#!#" & aText
-- Get the text after the leading white space
set prvDlmt to text item delimiters
set text item delimiters to "#!#BEGINNING#!#" & leadingWhiteSpace
set aText to text item 2 of aText
set text item delimiters to prvDlmt
(* Strip trailing white space *)
if aText is "" then return aText
-- Initialize the collector variable
set trailingWhiteSpace to ""
-- Define the last character to start at
set i to count of characters in aText
repeat
-- Is this character still whitespace?
if (ASCII number (character i of aText)) > 32 and (ASCII number (character i of aText)) ≠ 202 then
exit repeat -- No more white space; stop collecting it
else
-- Collect white space
set trailingWhiteSpace to character i of aText & trailingWhiteSpace
set i to i - 1
end if
end repeat
-- Is there any white space?
if (count of characters in trailingWhiteSpace) is 0 then return aText
-- Mark the end of the text
set aText to aText & "#!#THE_END#!#"
-- Get the part of the text before the trailing white space
set prvDlmt to text item delimiters
set text item delimiters to trailingWhiteSpace & "#!#THE_END#!#"
set aText to text item 1 of aText
set text item delimiters to prvDlmt
return aText
on error eMsg number eNum
error "trim: " & eMsg number eNum
end try
end trim
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment