1

In a script, I need to put rich text from the pasteboard into TextEdit. This works as expected in AppleScript:

tell application "TextEdit"
    activate
    set myrtf to the clipboard as «class RTF »
    set mydoc to make new document
    set text of mydoc to myrtf
end tell

However, I need to use JXA, and I can’t figure out how to translate the above AppleScript to that.

One (solved) issue is that in JXA, you can read any pasteboard content other than plain text only using the JXA-Objective-C bridge. But from then on, I’m stuck. Either I end up with plain text containing the raw RTF attributed string ("{\\rtf1\\ansi\\ansicpg1252\\cocoartf1671\\cocoasubrtf600\n{\\fonttbl…) or I get a conversion error (-10000). Here is what I tried:

var TextEdit = Application('TextEdit');
TextEdit.includeStandardAdditions = true;
TextEdit.activate();

ObjC.import('AppKit');
var content = $.NSPasteboard.generalPasteboard.stringForType('public.rtf');
var data = content.dataUsingEncoding('NSUTF8StringEncoding');
var string = $.NSAttributedString.alloc.initWithRTFDocumentAttributes(data, '0');

var mydoc = TextEdit.Document().make();
mydoc.text = content.js; // or data.js or string.js

If I use content.js in the last line, I get the raw RTF attributed string mentioned above, if I use data.jsor string.jsinstead, I get Error -10000.

It must be possible to translate the simple AppleScript above to JXA. Where is my mistake?

Uli Zappe
  • 306
  • 3
  • 8
  • You probably tried this and discarded it, but I did discover that “as” in the call to theClipboard is accepted: `mytext = TextEdit.theClipboard({as:"text"})` and also `as:"string"`; I can't discover any other options than "text" and "string". Everything else I try fails with your Error -10000. – Jerry Stratton Jan 14 '22 at 00:53
  • Yep; that’s why I went the JXA-Objective-C bridge route. – Uli Zappe Jan 14 '22 at 02:26

1 Answers1

2

Stuff that works in AppleScript often breaks in JXA. It’s half-baked, flawed, and abandoned. That’s why no-one uses it.

In this case, JXA’s built-in Apple event bridge 1. botches how typeType and typeEnumerated descriptors are bridged to/from JS (it overloads JS strings instead of defining a Symbol type), and 2. provides no way to create raw Apple event descriptors such as «class RTF » (a descriptor of typeType containing a 4-byte value of OSType written in AS as a four-char code surrounded by chevrons).

(You can build that descriptor using +[NSAppleEventDescriptor descriptorWithTypeCode:], but JXA’s AE bridge doesn’t understand its ObjC bridge, and vice-versa.)

Use AppleScript if you can, bearing in mind that OSA support for RTF data is dire throughout, or even avoid OSA langs entirely and write your code in ObjC/Swift, using Cocoa APIs to access the clipboard and write RTF files. If you want further advice, post a general description of what you are trying to do, as opposed to how you’re trying to do it.

foo
  • 166
  • 1
  • 3
  • Well, I for one use it a lot. I’m aware of its pitiful state and just wanted to know if what I want to do is possible nevertheless. What I want is exactly what I describe, only that the actual application is not TextEdit, but another one with the same AppleScript interface as far as my task is concerned. I want to automate creating documents in this application and putting rich text into them from the pasteboard. (If all else fails I could use simulating the Command and v keys.) So you say it’s impossible to even create an AppleScript rich text string from …stringForType('public.rtf')? – Uli Zappe Jan 16 '22 at 22:28
  • There’s no such thing as an “AppleScript rich text string”; AppleScript itself supports plain text only. Scriptable apps that work with styled text typically represent that text as part of their “object model”, allowing you to manipulate both the characters and their styles by setting “object” attributes, e.g. `set color of word 1 to {0,0,65535}`. That Cocoa apps allow you to `set text to «data RTF …»`is a special-case behavior. With `the clipboard as «class RTF »` command, the RTF data is returned as an opaque «data…» blob; essentially a raw `AEDesc` value. – foo Jan 17 '22 at 05:59
  • And as I say, there’s no equivalent to AS’s chevron syntax in JXA, so you’re SOOL for `«class…»`, `«constant…»`, `«data…»`, `«command…»`. You can’t get `the clipboard` to return RTF data because there’s no AppleScript keyword for an RTF type, and no way to write the four-char code `«class RTF »`. As for `NSPasteboard` APIs, those give you Cocoa objects (e.g. `NSAttributedString`) which JXA’s Apple event bridge doesn’t recognize. Your only option there would be to build and send an Apple event using `NSAppleEventDescriptor` APIs. Emulating “Cmd-V” is probably easiest though. – foo Jan 17 '22 at 06:21