Basically, I need to make an array containing plaintext strings, the first containing all keys for the string “replace” and then a matching array containing the replacements “with”
I need to be able to read these without knowing the set amounts the plist contains because it can change easily.
AppleScript does support plist reading. System Events contains a Property List Suite
which provides classes to parse property lists quite easy.
Try this
set globalUserPreferencesFile to (path to preferences folder as text) & ".GlobalPreferences.plist"
set plainTextList to {}
tell application "System Events"
set plistFile to property list file globalUserPreferencesFile
set NSUserReplacementItems to property list item "NSUserReplacementItems" of contents of plistFile
repeat with anItem in property list items of NSUserReplacementItems
set itemTextRepresentation to "on: "
set itemValue to value of anItem
try
set onValue to itemValue's |on|
set itemTextRepresentation to itemTextRepresentation & onValue & tab
on error
set itemTextRepresentation to itemTextRepresentation & "0" & tab
end try
set itemTextRepresentation to itemTextRepresentation & "replace: " & itemValue's replace & tab
set itemTextRepresentation to itemTextRepresentation & "with: " & itemValue's |with|
set end of plainTextList to itemTextRepresentation
end repeat
end tell
set {TID, text item delimiters} to {text item delimiters, return}
set plainTextList to plainTextList as text
set text item delimiters to TID
plainTextList
set replaceList to {}
set withList to {}
set theFile to (path to preferences folder from user domain) & ".GlobalPreferences.plist" as string
tell application "System Events"
set PLRoot to contents of property list file theFile
if "NSUserReplacementItems" is in name of property list items of PLRoot then
tell property list item "NSUserReplacementItems" of PLRoot
repeat with i from 1 to count (property list items)
set replacementItem to value of property list item i
set end of replaceList to replace of replacementItem
set end of withList to |with| of replacementItem
end repeat
end tell
end if
end tell
return {replaceList, withList}
or when you need to consider the on or off state (check box state in system preferences). The code above returns all replacements while the code below only returns if property ‘on’ is 1.
set replaceList to {}
set withList to {}
set theFile to (path to preferences folder from user domain) & ".GlobalPreferences.plist" as string
tell application "System Events"
set PLRoot to contents of property list file theFile
if "NSUserReplacementItems" is in name of property list items of PLRoot then
tell property list item "NSUserReplacementItems" of PLRoot
repeat with i from 1 to count (property list items)
set replacementItem to (value of property list item i) & {replace:"", |on|:0, |with|:""} --default values
if (|on| of replacementItem) as boolean then
set end of replaceList to replace of replacementItem
set end of withList to |with| of replacementItem
end if
end repeat
end tell
end if
end tell
return {replaceList, withList}
edit: Stefan’s post didn’t exists when I was creating this post. Also updated the script more to the wishes of TS
I have just one last query, I am nearly finished with the script but It’s currently too easy to break:
So far it extracts the plist data into the arrays thanks to your scripts.
I have it starting up system preferences, going into the text replacement section and beginning to add the text replacements, but it always breaks after the first one…
Do you have a better method for adding text replacements instead of the following:
set shortcutList to {}
set withList to {}
set theFile to "/Volumes/MATSTARES/ENUserData/.GlobalPreferences.plist" as string
tell application "System Events"
set PLRoot to contents of property list file theFile
if "NSUserReplacementItems" is in name of property list items of PLRoot then
tell property list item "NSUserReplacementItems" of PLRoot
set totalReplacements to count (property list items)
repeat with i from 1 to count (property list items)
set replacementItem to (value of property list item i) & {replace:"", |on|:0, |with|:""} --default values
if (|on| of replacementItem) as boolean then
set end of shortcutList to replace of replacementItem
set end of withList to |with| of replacementItem
end if
end repeat
end tell
tell process "System Preferences"
delay 2
click menu item "Language & Text" of menu "View" of menu bar 1
tell window "Language & Text"
delay 1
click radio button "Text" of tab group 1
delay 1
repeat with i from 1 to totalReplacements
click button 1 of tab group 1
set the clipboard to item i of shortcutList
keystroke "v" using {command down}
keystroke tab
set the clipboard to item i of withList
keystroke "v" using {command down}
end repeat
end tell
end tell
end if
end tell
Thankyou for the response, but there isn’t one for the text replacements, they’re saved in .GlobalPreferences.plist, which is only read once (on login), so I need to GUI script them in because they need to be added without needing to log out and back in.
setGlobalReplacementItem(" /0 ", " ø ", false)
on setGlobalReplacementItem(_replace, _with, _state)
set replacementItem to {replace:_replace, |on|:_state as integer, |with|:_with}
set theFile to (path to preferences folder from user domain) & ".GlobalPreferences.plist" as string
tell application "System Events"
set PLRoot to contents of property list file theFile
if "NSUserReplacementItems" is not in name of property list items of PLRoot then
set r to make new property list item at end of PLRoot with properties {kind:list, name:"NSUserReplacementItems", value:{}}
end if
tell property list item "NSUserReplacementItems" of PLRoot
repeat with i from 1 to count (property list items)
set currentItem to (value of property list item i) & {|on|:0} --if no on key then set to 0
if replace of currentItem is equal to replace of replacementItem then
set value of property list item i to replacementItem
return --there is no reason to continue
end if
end repeat
make new property list item at end of it with properties {kind:record, value:replacementItem}
end tell
end tell
end setGlobalReplacementItem
It checks if there is an entry NSUserReplacementItems in the plist file, if not create one. Then it checks if the given replace string is already in there, if it’s in there then replace it with the new value. At last, if the replace string can’t be found, add it to end of NSUserReplacementItems property.
Unfortunately, like McUsr mentioned, editing this file outside System Preferences will not take immediate effect. The system needs to reload the file first so there are three things you can do:
give the system a restart command
give the user a notification that the changed will take affect after relogin
run the script, start system preferences, show the localization pane, click ‘Show All’ button and close system preferences.
This will copy the NSUserReplacementItems from MATSTARES volume to you user’s preference folder.
I don’t know what the volume MATSTARES is (USB, Optical, AFP, SMB, NFS, FUSE etc…), and can’t give a good example.
If you can download or mount the volume at startup you can use the command (for a mounted volume) and save it as arguments in an start up item. This way if you reboot the system it has always the latest version of your server’s globalPreferences.
I picked the name of the anchor out of the bundle for the preference pane for the anchor, in the /System/Library/Preference/Panes/Localization.prefPane/Contents/Resourses/English.lproj/InfoPlist.strings
tell application "System Preferences"
reveal anchor "Formats" of pane "com.apple.Localization"
activate
end tell
I very very much appreciate the help you guys have provided, it’s simply amazing how helpful this community is; You guys are epic!
Just got one last favor to ask: I’ve tried to use your codes and have it backing up the plist data and have a loop ready to go for inputting it, but I can’t target the inputs properly I can have it use the auto-focus and assume it’s targetted but that’s really prone to breaking if the user makes another window active mid-script.
How can I target these elements specifically?
The “+” button; I can click it by using
click button 1 of tab group 1
Input the plist info into the text field “Replace” (the highlighted one), and have it input it regardless of active window (rather than assuming it’s active, which is the issue I have currently)
I’ve tried with similar variants to this:
set value of text field 1 of table row 66 of table 0 to "hello world"
TextField 1 of row 1 of table 1 of scroll area 1 of tab group 1
Then input the other info into the right hand text field; “With”
And loop between adding them all one after another (And if you’re feeling generous, ensuring there are no duplicates before looping)
I am not totally sure of this, but I expect the abbreviations to be same as the one that can be defined by cocoa text bindings, look at Create custom keybindings - Mac OS X Hints and see if that is usable.
And, if you don’t have the developer tools, I think it is time for you to get them. In there is a utility named UIELementInspector.app. I think the usage of it is explained at macosxautomation.com.
Edit
There are also some tools and tricks to be found here. For extracting properties of elements in general, and some targetting UI Elements specially.
Kai Edwards posted a nice article about extracting properties in Unscripted.
Edit++ I guess you use the UIElementor.app If the focusing of the window is a problem, couldn’t you set its status to focused, between each step. You should have a very fast user if he manages to interfere then!
My idea is, that it is better to add them programatically, and then maybe just invoking the preference pane, and then “show all” to make them take effect, in order to avoid the UI scripting almost all together.