This script changes various attributes of the RTF(D) clipboard to the values of the frontmost Tinderbox.
Usage
-
Copy, e.g. in Safari
-
Run script
-
Paste
Setup
Properties are independent (except changeCodeFont
which is only used if changeFont
is true
).
-
changeFont
: Change font to$TextFont
. -
changeCodeFont
: Change mono spaced font to$CodeFont
. -
changeFontSize
: Change font size to$TextFontSize
. -
changeParagraphStyle
: Change line height to$LineSpacing
and paragraph spacing to$ParagraphSpacing
. -
changeColor
: Change text color to$TextColor
. -
removeBackgroundColor
: Remove background color. -
ensureDoubleLinebreak
: Remove line separators (U+2028). If$ParagraphSpacing
= 0 replace multiple linefeeds with double linefeed, else with single linefeed. -
ensureLinebreakAtEnd
: Add linefeed at end (if necessary). Useful for transclusion. -
removeImages
: Use RTF instead of RTFD.
Running it via Alfred’s NSAppleScript action is very fast, so if you can I’d suggest using that.
Here's how to use Alfred's NSAppleScript
-
Contextual menu >
Actions
>Run NSAppleScript
-
Embed script in Alfred’s NSAppleScript handler
-- use statements and properties
use AppleScript version "2.4"
property changeFont :
property changeCodeFont: …
-- alfred handler
on alfred_script(q)
-- script goes here (without use statements, properties and handler)
end alfred_script
-- handler
on convertFontToFamily …
- Tick checkbox
Cache compiled AppleScript
Installing fonts
Depending on the font you’re using in a Tinderbox it might be necessary to first install the font.
Note: Make sure that you’re allowed to install a given font.
Tinderbox’s default fontMercurySSm-Book
is not licensed for usage outside of Tinderbox.
-
Find
Tinderbox.app
in Finder -
Contextual menu >
Show Package Contents
-
Open folder
Contents
-
Open folder
Resources
-
Open folder
fonts
-
Double click font
(This opensFontBook.app
) -
Confirm
FontBook.app
’s dialog by clickingInstall
Examples
Note: I have $ParagraphSpacing
set to 0, thus the script added double linebreaks.
The script is probably not in its final state, I didn’t do much testing and am not sure whether the regexes are ok. Feedback is of course very welcome, if you have ideas I’d like to know them, if you have questions please don’t hesitate to ask.
Script
-- Transform pasteboard for pasting into Tinderbox
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions
property changeFont : true -- Change font to $TextFont.
property changeCodeFont : true -- Change mono spaced font to $CodeFont.
property changeFontSize : true -- Change font size to $TextFontSize.
property changeParagraphStyle : true -- Change line height to $LineSpacing and paragraph spacing to $ParagraphSpacing.
property changeColor : true -- Change text color to $TextColor.
property removeBackgroundColor : true -- Remove background color.
property ensureDoubleLinebreak : true -- Remove line separators (U+2028) and replace multiple linefeeds with double linefeed.
property ensureLinebreakAtEnd : true -- Add linefeed at end (if necessary). Useful for transclusion.
property removeImages : false -- Use RTF instead of RTFD clipboard.
try
---------------------------------------------------------- Get Tinderbox Attributes -----------------------------------------------------------
tell application id "com.eastgate.Tinderbox-9"
try
if not (exists front document) then error "Please open a Tinderbox"
tell front document
set theFontName to value of attribute "TextFont"
set theFontSize to value of attribute "TextFontSize"
set theMonoFontName to value of attribute "CodeFont"
set theTextColor_Tinderbox to value of attribute "TextColor"
set theLineSpacing_Tinderbox to value of attribute "LineSpacing"
set theParagraphSpacing_Tinderbox to value of attribute "ParagraphSpacing"
end tell
on error error_message number error_number
if the error_number is not -128 then display alert "Tinderbox" message error_message as warning
error number -128
end try
end tell
set theFontSize to theFontSize as real
set theFont to current application's NSFont's fontWithName:(theFontName) |size|:theFontSize
if theFont = missing value then error "Font \"" & theFontName & "\" is not installed on your mac." & linefeed & linefeed & "See https://forum.eastgate.com/t/script-transform-pasteboard-for-pasting-into-tinderbox/4986"
set theFont_FamilyName to theFont's familyName()
set theMonoFont to current application's NSFont's fontWithName:(theMonoFontName) |size|:theFontSize
if (theMonoFont = missing value) or not ((theMonoFont's isFixedPitch()) as boolean) then error "Font \"" & theMonoFontName & "\" is not installed on your mac." & linefeed & linefeed & "See https://forum.eastgate.com/t/script-transform-pasteboard-for-pasting-into-tinderbox/4986"
set theMonoFont_FamilyName to theMonoFont's familyName()
set theLineSpacing to ((theLineSpacing_Tinderbox as integer) / 100) as real
set theParagraphSpacing to theParagraphSpacing_Tinderbox as integer
--------------------------------------------------------------- Get Pasteboard ----------------------------------------------------------------
set theAttributedString to missing value
set theNSPasteboardTypeRTFD to current application's NSPasteboardTypeRTFD
set theNSPasteboardTypeRTF to current application's NSPasteboardTypeRTF
set thePasteboard to current application's NSPasteboard's generalPasteboard()
set thePasteboardItems to thePasteboard's pasteboardItems()
set thePasteboardDataArray to current application's NSMutableArray's new()
repeat with i from 0 to ((thePasteboardItems's |count|()) - 1)
set thePasteboardItem to (thePasteboardItems's objectAtIndex:i)
set thePasteboardItem_Types to thePasteboardItem's |types|()
if not removeImages and (thePasteboardItem_Types's containsObject:theNSPasteboardTypeRTFD) then
set thePasteboardItem_Data to (thePasteboardItem's dataForType:theNSPasteboardTypeRTFD)
set theAttributedString to (current application's NSAttributedString's alloc()'s initWithData:thePasteboardItem_Data options:(missing value) documentAttributes:(missing value) |error|:(missing value))
else if (thePasteboardItem_Types's containsObject:theNSPasteboardTypeRTF) then
set thePasteboardItem_Data to (thePasteboardItem's dataForType:theNSPasteboardTypeRTF)
set theAttributedString to (current application's NSAttributedString's alloc()'s initWithData:thePasteboardItem_Data options:(missing value) documentAttributes:(missing value) |error|:(missing value))
end if
if (thePasteboardItem_Types's containsObject:"com.apple.webarchive") then
(thePasteboardDataArray's addObject:({PasteboardType:"com.apple.webarchive", PasteboardData:(thePasteboardItem's dataForType:"com.apple.webarchive")}))
end if
if theAttributedString ≠ missing value then
exit repeat
end if
end repeat
if theAttributedString = missing value then error "No RTFD or RTF in Clipboard"
set theMutableAttributedString to theAttributedString's mutableCopy()
------------------------------------------- Ensure Double Linebreak: Remove Line Separators --------------------------------------------
if ensureDoubleLinebreak then
set theMutableAttributedString to my regexReplaceAttributedString(theMutableAttributedString, {location:0, |length|:theMutableAttributedString's |length|()}, "(?m:(\\p{Zl}+))", "")
end if
-------------------------------------------------------- Change Font And Font Size ---------------------------------------------------------
set theMutableAttributedString_Length to theMutableAttributedString's |length|()
if changeFont or changeFontSize then
set theLocation to 0
set theAttribute to current application's NSFontAttributeName
set theFontManager to current application's NSFontManager's sharedFontManager()
if ensureDoubleLinebreak then set theAttributesArray to current application's NSMutableArray's new()
repeat while (theLocation < theMutableAttributedString_Length)
set {thisFont, thisFontRange} to theMutableAttributedString's |attribute|:theAttribute atIndex:(theLocation) longestEffectiveRange:(reference) inRange:{location:theLocation, |length|:(theMutableAttributedString_Length - theLocation)}
if changeFont and changeFontSize then
set thisNewFont to my convertFontToFamily(theFontManager, thisFont, theFontSize, theFont_FamilyName, theMonoFont_FamilyName)
else if changeFont then
set thisNewFont to my convertFontToFamily(theFontManager, thisFont, (thisFont's |pointSize|()), theFont_FamilyName, theMonoFont_FamilyName)
else if changeFontSize then
set thisNewFont to (theFontManager's convertFont:(thisFont) toSize:theFontSize)
end if
(theMutableAttributedString's removeAttribute:theAttribute range:thisFontRange)
(theMutableAttributedString's addAttribute:theAttribute value:thisNewFont range:thisFontRange)
if ensureDoubleLinebreak then theAttributesArray's addObject:{|Font|:thisFont, FontRange:thisFontRange, FontIsFixedPitch:(thisFont's isFixedPitch())}
set theLocation to theLocation + (thisFontRange's |length|())
end repeat
else
if ensureDoubleLinebreak then
set theLocation to 0
set theAttribute to current application's NSFontAttributeName
set theAttributesArray to current application's NSMutableArray's new()
repeat while (theLocation < theMutableAttributedString_Length)
set {thisFont, thisFontRange} to theAttributedString's |attribute|:theAttribute atIndex:(theLocation) longestEffectiveRange:(reference) inRange:{location:theLocation, |length|:(theMutableAttributedString_Length - theLocation)}
theAttributesArray's addObject:{|Font|:thisFont, FontRange:thisFontRange, FontIsFixedPitch:(thisFont's isFixedPitch())}
set theLocation to theLocation + (thisFontRange's |length|())
end repeat
end if
end if
-------------------------------- Ensure Double Linebreak: Replace Linefeeds In Non-Mono-Spaced Font ---------------------------------
if ensureDoubleLinebreak then
set theFontRangesArray to (theAttributesArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:("self.FontIsFixedPitch = false")))'s valueForKey:"FontRange"
set theFontRangesArray_Count to theFontRangesArray's |count|()
set theFontRangesUnitedArray to current application's NSMutableArray's new()
set i to 0
repeat while i ≤ (theFontRangesArray_Count - 1)
set thisRange to (theFontRangesArray's objectAtIndex:i)
set theRange to thisRange
if i < (theFontRangesArray_Count - 1) then
repeat with j from (i + 1) to (theFontRangesArray_Count - 1)
set thisNextRange to (theFontRangesArray's objectAtIndex:j)
set isLocationInRange to current application's NSRange's NSLocationInRange((current application's NSRange's NSMaxRange(theRange)), thisNextRange)
if isLocationInRange then
set theRange to current application's NSRange's NSUnionRange(theRange, thisNextRange)
set i to i + 1
else
exit repeat
end if
end repeat
end if
theFontRangesUnitedArray's insertObject:(theRange) atIndex:0
set i to i + 1
end repeat
set thePattern to "(?m:(((\\t+)?\\n)+))"
repeat with i from 0 to ((theFontRangesUnitedArray's |count|()) - 1)
set thisRange to (theFontRangesUnitedArray's objectAtIndex:i)
set thisRange_Location to (thisRange's location) as integer
if thisRange_Location > 0 then
set thisRange_modified to {location:thisRange_Location - 1, |length|:((thisRange's |length|) as integer) + 1}
else
set thisRange_modified to thisRange
end if
if theParagraphSpacing > 0 then
set theMutableAttributedString to my regexReplaceAttributedString(theMutableAttributedString, thisRange_modified, thePattern, linefeed)
else
set theMutableAttributedString to my regexReplaceAttributedString(theMutableAttributedString, thisRange_modified, thePattern, linefeed & linefeed)
end if
end repeat
end if
set theMutableAttributedString_Length to theMutableAttributedString's |length|()
--------------------------------------------------- Change Line And Paragraph Spacing ----------------------------------------------------
if changeParagraphStyle then
set theLocation to 0
set theAttribute to current application's NSParagraphStyleAttributeName
repeat while (theLocation < theMutableAttributedString_Length)
set {thisParagraphStyle, thisParagraphStyleRange} to theMutableAttributedString's |attribute|:theAttribute atIndex:(theLocation) longestEffectiveRange:(reference) inRange:{location:theLocation, |length|:(theMutableAttributedString_Length - theLocation)}
set thisMutableParagraphStyle to thisParagraphStyle's mutableCopy()
thisMutableParagraphStyle's setParagraphSpacing:theParagraphSpacing
thisMutableParagraphStyle's setLineHeightMultiple:theLineSpacing
thisMutableParagraphStyle's setMinimumLineHeight:0
thisMutableParagraphStyle's setMaximumLineHeight:0
(theMutableAttributedString's removeAttribute:theAttribute range:thisParagraphStyleRange)
(theMutableAttributedString's addAttribute:theAttribute value:thisMutableParagraphStyle range:thisParagraphStyleRange)
set theLocation to theLocation + (thisParagraphStyleRange's |length|())
end repeat
end if
---------------------------------------------------------------- Change Color -----------------------------------------------------------------
if changeColor then
set {R, G, B} to my getNSRGBFromHex(theTextColor_Tinderbox)
set theTextColor to current application's NSColor's colorWithRed:(R) green:(G) blue:(B) alpha:(1)
theMutableAttributedString's removeAttribute:(current application's NSForegroundColorAttributeName) range:{location:0, |length|:theMutableAttributedString_Length}
theMutableAttributedString's addAttribute:(current application's NSForegroundColorAttributeName) value:theTextColor range:{location:0, |length|:theMutableAttributedString_Length}
end if
--------------------------------------------------------- Remove Background Color ----------------------------------------------------------
if removeBackgroundColor then
theMutableAttributedString's removeAttribute:(current application's NSBackgroundColorAttributeName) range:{location:0, |length|:theMutableAttributedString_Length}
end if
---------------------------------------------------------- Ensure Linebreak At End -----------------------------------------------------------
if ensureLinebreakAtEnd then
if not ((theMutableAttributedString's |string|())'s hasSuffix:linefeed) then
set theParagraphStyleAttribute to (theMutableAttributedString's |attribute|:(current application's NSParagraphStyleAttributeName) atIndex:((theMutableAttributedString's |length|()) - 1) effectiveRange:(missing value))
theMutableAttributedString's appendAttributedString:(current application's NSAttributedString's alloc()'s initWithString:linefeed attributes:{NSParagraphStyle:theParagraphStyleAttribute})
end if
end if
--------------------------------------------------------------- Set Pasteboard ----------------------------------------------------------------
set theMutableAttributedString_Range to {location:0, |length|:theMutableAttributedString's |length|()}
if (theMutableAttributedString's containsAttachmentsInRange:theMutableAttributedString_Range) then
set theDocumentAttributes to current application's NSDictionary's dictionaryWithDictionary:{NSDocumentTypeDocumentAttribute:(current application's NSRTFDTextDocumentType)}
set theData to theMutableAttributedString's RTFDFromRange:(theMutableAttributedString_Range) documentAttributes:theDocumentAttributes
set theType to theNSPasteboardTypeRTFD
else
set theDocumentAttributes to current application's NSDictionary's dictionaryWithDictionary:{NSDocumentTypeDocumentAttribute:(current application's NSRTFTextDocumentType)}
set theData to theMutableAttributedString's RTFFromRange:(theMutableAttributedString_Range) documentAttributes:theDocumentAttributes
set theType to theNSPasteboardTypeRTF
end if
(thePasteboardDataArray's addObject:({PasteboardData:theData, PasteboardType:theType}))
thePasteboard's clearContents()
repeat with i from 0 to (thePasteboardDataArray's |count|()) - 1
(thePasteboard's setData:((thePasteboardDataArray's objectAtIndex:i)'s valueForKey:"PasteboardData") forType:((thePasteboardDataArray's objectAtIndex:i)'s valueForKey:"PasteboardType"))
end repeat
display notification "Formatted" with title "Transform Pasteboard"
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: \"Transform Pasteboard: Tinderbox\"" message error_message as warning
error number -128
end try
on convertFontToFamily(theFontManager, theFont, theFontSize, theFont_FamilyName, theMonoFont_FamilyName)
try
set theNewFont to (theFontManager's convertFont:(theFont) toSize:theFontSize)
if not ((theFont's isFixedPitch()) as boolean) then
set theNewFont to (theFontManager's convertFont:theNewFont toFamily:theFont_FamilyName)
else
if changeCodeFont then
set theNewFont to (theFontManager's convertFont:theNewFont toFamily:theMonoFont_FamilyName)
end if
end if
return theNewFont
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"convertFontToFamily\"" message error_message as warning
error number -128
end try
end convertFontToFamily
on regexReplaceAttributedString(theMutableAttributedString, theRange, thePattern, theReplacementPattern)
try
set {theRegex, theError} to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:0 |error|:(reference)
if theRegex = missing value then error theError's localizedDescription() as string
set theMutableAttributedString_String to theMutableAttributedString's |string|()
set theMatches to (theRegex's matchesInString:theMutableAttributedString_String options:0 range:theRange) as list
set theMatches to reverse of theMatches
repeat with thisMatch in theMatches
(theMutableAttributedString's replaceCharactersInRange:(thisMatch's range()) withString:theReplacementPattern)
end repeat
return theMutableAttributedString
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"regexReplaceAttributedString\"" message error_message as warning
error number -128
end try
end regexReplaceAttributedString
on getNSRGBFromHex(theHTMLColor) -- #xxxxxx (based on https://macscripter.net/viewtopic.php?pid=95048#p95048)
try
set theHexList to "0123456789ABCDEF"
set theNSRGBList to {}
repeat with i from 2 to 6 by 2
set end of theNSRGBList to ((((offset of theHTMLColor's character i in theHexList) - 1) * 16) + (offset of theHTMLColor's character (i + 1) in theHexList) - 1) / 255
end repeat
return theNSRGBList
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"getNSRGBFromHex\"" message error_message as warning
error number -128
end try
end getNSRGBFromHex