1

My app supports being scripted with Applescript.

I am trying to make styled text content, stored in NSAttributedString objects, available to an Applescript user.

I thought I could simply deliver styled text with the NSAttributedString class, just like I deliver plain text with the NSString class, but that does not work - Cocoa Scripting then reports that it cannot convert or coerce the data.

I wonder if I'm missing something or if this is just plain impossible with the standard classes supported by Cocoa Scripting?

AppleScript does know the "styled text" type, as seen in this example:

set stxt to "foo" as styled text

So, if AppleScript knows this type by default, shouldn't the Cocoa Scripting engine support it as well somehow?

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • Basically styled text is RTF and the clipboard has several representations (you can see that in AppleScript to `get the clipboard as record`. But as far as I know you have to write all RTF related code by yourself, there is no implicit coercion/conversion. – vadian Apr 01 '16 at 18:54
  • Oh, I know all about the clipboard and its rich text formats. I have no problem converting it to RTF, for instance. But that doesn't help me with providing the data to Applescript, or does it? My app could put the rich text into the clipboard and then the Applescript would take it out that way again, but that's quite a hack. But I'll take that as a last resort, thanks for the idea. – Thomas Tempelmann Apr 01 '16 at 19:00
  • Tut mir leid, ich wollte deine Kenntnisse nicht herabwürdigen (sorry, I didn't want to debase your skills). Try to create a custom value-type and map it to NSAttributedString. You have to implement `scriptingWithDescriptor` and `scriptingDescriptor` to convert the type from and to `NSAppleEventDescriptor` – vadian Apr 01 '16 at 19:16
  • I wasn't offended, if you thought that. I was rather excited to say that because this app I'm working on is a clipboard manager ;) Anyway, I had already tried to set the type my property to "any", which then sends me the NSAppleEventDescriptor, but that still only seems to contain plain text, i.e. the scripting engine appears to convert the "styled text" to plain text even before giving it to me. Or do you know that this should work, i.e. have you done this successfully? Then I must be missing something from your suggestion. – Thomas Tempelmann Apr 01 '16 at 19:39
  • Oh, I misunderstood. Only now I know what you meant by "as record". I had no idea what that did. Now I have to figure out how to use that in my code. – Thomas Tempelmann Apr 02 '16 at 08:42
  • @ThomasTempelmann, this may not be what you need, but I thought I would just mention it in case. You might try scripting a highly-scriptable app like [Tex-Edit Plus ](http://www.tex-edit.com/) for display/control of rich text. It is shareware, free unless you want to pay the $15 price. – JMichaelTX Apr 02 '16 at 17:50

2 Answers2

1

As always there are many choices for solving an AS problem. In my scriptable text editor (Ted), I implemented the Text Suite, which is based on rich text (NSTextStorage, a subclass of NSMutableAttributedString). I wanted to be able to script tabs in my paragraphs, so I added a style record, which contains all the paragraph style information. This lets me write scripts like this:

tell application "Ted"
    set doc1 to make new document at beginning with properties {name:"Document One"}
    tell doc1
        set p1 to make new paragraph at end with data "Paragraph One" with properties {size:24, color:maraschino}
        set p2 to make new paragraph at end with data "Paragraph Two" with properties {style:style of paragraph 1}
        set color of paragraph 1 to blue
    end tell

    set doc2 to make new document at beginning with properties {name:"Document Two"}
    copy p1 to beginning of doc2
    properties of paragraph 1 of doc2       
end tell

Since p1 is rich text, the second document ends up with both the text and formatting of the first paragraph of the first document.

You can also ask for the properties of a piece of text, where I have implemented the usual Text Suite properties, as well as a "style" property for paragraph style (backed by NSParagraphStyle, since I wanted to be able to script the tab stops):

properties of paragraph 1 of doc2       

Result: {height:60.0, italic:false, size:24, style:{paragraph spacing after:0.0, head indent:0.0, line break mode:0, alignment:4, line spacing:0.0, minimum line height:0.0, first line head indent:0.0, paragraph spacing before:0.0, tabs:{"28L", "56L", "84L", "112L", "140L", "168L", "196L", "224L", "252L", "280L", "308L", "336L"}, tail indent:0.0, maximum line height:0.0, line height multiple:0.0, default tab interval:0.0}, color:blue, width:164.109375, font:"Helvetica", bold:false, class:attribute run}

This works well for passing rich text within my application, but may not be as useful for passing styled text to other applications, which may be what you wanted to do. I think adding a "style" property (of type record) is probably the best way to convey style info for use in other scriptable apps. Then in the second app, the scripter can make use of any properties in the style record that the second app understands.

Ron Reuter
  • 1,287
  • 1
  • 8
  • 14
  • My app deals with original clipboard data, but in more detail (the built-in `the clipboard` can't handle newer flavors for which there is no known 4-char-code, but mine can as it provides access to the UTI). I have now simply added a "raw data" accessor that returns the data with the 4-char-code (if available), which is similar to what one gets from `the clipboard as record`. I would have liked to use a more universal format that's shared between apps, but that appears not to exist. – Thomas Tempelmann Apr 26 '16 at 11:53
  • 1
    Take a look at the typeStyledText 'STXT' record (defined in Apple Event Registry), which includes a typeChar descriptor for the plain text and a typeScrapStyles for the style information. "The keyAEStyles field contains the style information for the text as it would be stored in the 'styl' scrap type on the Clipboard." Is this the "more universal format" you're looking for? – Ron Reuter Apr 26 '16 at 15:28
  • 1
    One important point of your answer, which I only realize now, is that I made the mistake of trying to return NSAttributedString objects where the sdef uses the type "text". Correct would be to instead instantiate my objects with the NSTextStorage class (using the same constructor as with NSAttributedString), add the Text Suite (taken from Apple's Sketch app sample code) and then use the "rich text" instead of the "text" type where I want to return styled text. Then a user can use the Text Suite commands to access the font and color properties. – Thomas Tempelmann May 08 '16 at 00:15
0

It looks like there is no implicit support for styled text in AppleScript. And there is also no common interchange record type for passing styled text.

AppleScript was developed in the pre-OSX days when styled text was often represented by a combination of a plain text (in System or MacRoman encoding) and a styl resource. With Unicode came an alternative format of a ustl style format. These are still used with the Carbon Pasteboard API (PasteboardCreate etc.) today. Yet, none of these seem to have made it into the use with AppleScript.

The fact that AppleScript knows of a styled text type has no special meaning. Even its class is just text.

Update

I just found that Matt Neuburg's book "AppleScript The Definitive Guide" mentions styled text and gives an example where it's indeed showing a record containing both the plain text (class ktxt) and style data (class ksty) with data of type styl, just as I had expected above. He also points out that most applications don't use that format, though.

So, it appears using a record with style resource data is indeed the intended way, only that hardly anyone knows about it. Go figure.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149