I am writing an AppleScript .scpt file, triggered system-wide by key combination assigned in FastScripts.app, that adds parentheses around the selected editable text.
If the selected text happens to already be wrapped in parentheses, then I want my script to effectively delete the parentheses from the selection. This is where I need assistance. I do not want to strip any of the formatting from formatted text.
My script works if the selection-with-parentheses is plain text data, but not if it is RTF or HTML data.
Here is my full code:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
(*
Get the selected text into an AppleScript, while preserving the original clipboard:
From: http://apple.stackexchange.com/questions/271161/how-to-get-the-selected-text-into-an-applescript-without-copying-the-text-to-th/
*)
-- Back up the original clipboard contents:
set savedClipboard to my fetchStorableClipboard()
set thePasteboard to current application's NSPasteboard's generalPasteboard()
set theCount to thePasteboard's changeCount()
-- Copy selected text to clipboard:
tell application "System Events" to keystroke "c" using {command down}
-- Check for changed clipboard:
repeat 20 times
if thePasteboard's changeCount() is not theCount then exit repeat
delay 0.1
end repeat
set firstCharacter to (character 1 of (the clipboard))
set lastCharacter to (character (length of (the clipboard))) of (the clipboard)
-- Remove the parentheses from the selection, if the selection is wrapped in parentheses:
if (firstCharacter is "(") and (lastCharacter is ")") then
-- The selection already has parentheses.
-- I must discern what class types are available for the clipboard content:
tell current application
set cbInfo to get (clipboard info) as string
if cbInfo contains "RTF" then
-- I need help here.
-- Remove the first and last characters of the rich text, while retaining the rich text formatting.
else if cbInfo contains "HTML" then
-- I need help here.
-- Remove the first and last characters of the HTML, while retaining formatting data.
else
-- The clipboard contains plain text.
-- Remove the first and last character of a plain text string:
set theSelectionWithoutParentheses to (text 2 thru -2 of (the clipboard))
set the clipboard to theSelectionWithoutParentheses
tell application "System Events" to keystroke "v" using {command down}
end if
end tell
else
-- The selection needs parentheses.
tell application "System Events" to keystroke "("
delay 0.1
tell application "System Events" to keystroke "v" using {command down}
delay 0.1
tell application "System Events" to keystroke ")"
end if
delay 1 -- Without this delay, may restore clipboard before pasting.
-- Restore clipboard:
my putOnClipboard:savedClipboard
on fetchStorableClipboard()
set aMutableArray to current application's NSMutableArray's array() -- used to store contents
-- get the pasteboard and then its pasteboard items
set thePasteboard to current application's NSPasteboard's generalPasteboard()
-- loop through pasteboard items
repeat with anItem in thePasteboard's pasteboardItems()
-- make a new pasteboard item to store existing item's stuff
set newPBItem to current application's NSPasteboardItem's alloc()'s init()
-- get the types of data stored on the pasteboard item
set theTypes to anItem's types()
-- for each type, get the corresponding data and store it all in the new pasteboard item
repeat with aType in theTypes
set theData to (anItem's dataForType:aType)'s mutableCopy()
if theData is not missing value then
(newPBItem's setData:theData forType:aType)
end if
end repeat
-- add new pasteboard item to array
(aMutableArray's addObject:newPBItem)
end repeat
return aMutableArray
end fetchStorableClipboard
on putOnClipboard:theArray
-- get pasteboard
set thePasteboard to current application's NSPasteboard's generalPasteboard()
-- clear it, then write new contents
thePasteboard's clearContents()
thePasteboard's writeObjects:theArray
end putOnClipboard:
Best Answer
With some help from
this comment by user @I0_ol on this very post,
this answer by user3439894 to a previous Ask Different post, and
this answer to a Stack Overflow post,
I have devised a solution to modify HTML or RTF clipboard content, and then put this modified content on the clipboard.
While we're at it, here's another method to remove outer parentheses from plain text clipboard data:
To remove outer parentheses from HTML clipboard data (while preserving the formatting data):
Both Method 1 and Method 2 to remove outer parentheses from RTF clipboard data (while preserving the formatting data), manipulate the RTF clipboard content by parsing this data as hex code:
Method 1:
Method 1 for modifying RTF clipboard data is conceivably susceptible to false positives, if the desired hex code is split between the second character of one hex pair and the first character of the following hex pair.
For example,
32
and85
, when side-by-side in the hex code, is also interpreted as28
, in the eyes of Method 1. Clearly, this is undesirable.Method 2:
Method 2 solves the issue, making a false positive like this impossible. This is because, before Method 2 analyzes the hex code, it first organizes the hex code
text
object into a binary-basedlist
object.Unlike Method 1, Method 2 interprets the hex code in pairs. Therefore, Method 2 is technically better:
However, note that Method 2 has been designed around the assumption that you are working with a two-character hex code delimiter.
If your hex code delimiter happens to exceed 2 characters, (such as the 8-character hex code delimiter for an opening double quotation mark
“
, which is5C273933
), you would have to rewrite theputStringIntoBinaryList()
subroutine accordingly (or use Method 1 instead, which is probably safe to use on a lengthy, 8-character hex code delimiter).