I want to be able to write tab-aligned text to a file. This macro takes a sample text input, splits it into columns at a user-defined delimiter, and aligns each column using tabs.
It then displays the result in a KM Display Text window and also writes it to `Tab Align Test.rtf' on the desktop.
I realise that for some reason the fonts are different, but if you copy/paste the KM window text to the TextEdit window, and set the fonts to be the same, it's still aligned:
If you use the Write Styled Text option to set the font when writing the file, you get a similar result, except that the written text is grey while the pasted text is white.
You'll need different approaches for aligning columns of text that use a monospaced font like Courier and a proportional font like Helvetica (TextEdit).
TextEdit apparently won't let you set Tabs on the ruler via AppleScript but for the proportional approach, you will need to set tabs for the document.
While the monospaced version can (and probably should) use multiple spaces to pad out the columns so each line is the same number of characters (which will always work), the proportional approach should separate columns by a single tab.
The key, then, is to have control over specifiy font and tabs. You have to determine which kind of font you are working with and then to simulate tabs with multiple spaces in a monospaced font or set them in your document for a proportional font using just one tab between columns.
Why not use tabs with a monospaced font? Well, you could, but you'd have to have control over the tab settings of the document. Programs like BBEdit have a global tab setting (specified as a number of spaces, say, 3 or 4) that you wouldn't want to change for a specific document so padding out the columns is safer is less efficient.
Why not use multiple tabs with proportional fonts? Well, you could, but it's more work if you have to edit them (in the ruler). Having just one to get to the next column makes the inevitable layout refinements more efficient.
I'm aware of this, which is why I've been using Menlo in both TextEdit and KM.
You can set the tab width for plain text, but not rich text, annoyingly.
My first port of call was a spaced version. Maybe it's good enough.
For the one-tab approach, you'd still have to manually set the tab length, which rules out writing to files in the background.
Agreed, but it's kind of moot unless you can set the tab width for .rtf files.
The thing I still don't understand is why copying the text from the Display Text window and pasting it into TextEdit does adjust the tab-stop width automatically. What's going on there?
Pasteboard items of different types in the clipboard.
Your script populates a public.utf8-plain-text pasteboard item, but no public.rtf pasteboard item is created.
In the case of copying manually from the display window, however, we do get a public.rtf pasteboard, which TextEdit will use in preference.
Textually represented, its contents is:
public.rtf as string:
{\rtf1\ansi\ansicpg1252\cocoartf2709
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
\pard\tx0\tx1120\tx2240\tx3360\tx4480\tx5600\tx6720\tx7840\tx8960\tx10080\tx11200\tx12320\tx13440\tx14560\tx15680\tx16800\tx17920\tx19040\tx20160\tx21280\tx22400\tx23520\tx24640\tx25760\tx26880\tx28000\tx29120\tx30240\tx31360\tx32480\tx33600\tx34720\pardirnatural
\f0\fs28\fsmilli14182 \cf2 Mamma just killed a man that's terrible! \
Put a gun against his head why?! \
Pulled my trigger makes sense I suppose... \
Now he's dead hello officer, I'd like to report a murder}
To achieve the same in your script, you may be able to apply /usr/bin/textutil to your plain text to obtain rtf, rather than leaving that stage to TextEdit, which seems to do something a bit complex – overriden perhaps by the editor's default font setting in the GUI.
When I run your macro I see Helvetica in TextEdit.
There are a variable number of tabs in the pasted text that pad out the columns in TextEdit. The line that begins with 'Put' has one to get to the second column while the one that begins with 'Now' has three. That seems to be what the variable Local__Text has.
Does your shell script specify a font ? (I may be missing something)
textutil uses Helvetica Light by default, and that's what is specified by the RTF header it is generating there.
One way to generate RTF with a specific font, is to construct HTML markup, and use textutil for an HTML -> RTF rewrite.
Another approach is to create your public.rtf pasteboard item directly, using the kind of RTF wrapping (heading and closing brace) obtained by manual copying from a KM display window:
The pasteboard created like this seems to paste in the way you hope for:
Expand disclosure triangle to view JS source
(() => {
"use strict";
ObjC.import("AppKit");
const main = () => {
const rtf = `{\\rtf1\\ansi\\ansicpg1252\\cocoartf2709
\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fnil\\fcharset0 Menlo-Regular;}
{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}
{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0\\cname textColor;}
\\pard\\tx0\\tx1120\\tx2240\\tx3360\\tx4480\\tx5600\\tx6720\\tx7840\\tx8960\\tx10080\\tx11200\\tx12320\\tx13440\\tx14560\\tx15680\\tx16800\\tx17920\\tx19040\\tx20160\\tx21280\\tx22400\\tx23520\\tx24640\\tx25760\\tx26880\\tx28000\\tx29120\\tx30240\\tx31360\\tx32480\\tx33600\\tx34720\\pardirnatural
\\f0\\fs28\\fsmilli14182 \\cf2 Mamma just killed a man that's terrible! \\
Put a gun against his head why?! \\
Pulled my trigger makes sense I suppose... \\
Now he's dead hello officer, I'd like to report a murder}`;
return setClipOfTextType("public.rtf")(
rtf
);
};
// --------------------- GENERIC ---------------------
// setClipOfTextType :: String -> String -> IO String
const setClipOfTextType = utiOrBundleID =>
txt => {
const pb = $.NSPasteboard.generalPasteboard;
return (
pb.clearContents,
pb.setStringForType(
$(txt),
utiOrBundleID
),
txt
);
};
return main();
})();
I meant I opened the resultant file and tried changing the font and size in TextEdit to see if that impacted the alignment.
I'm not sure why I thought font/size would make any difference when the tab markers aren't being changed. That seems to be the difference when you paste the KM displayed text into TextEdit.
Ok this is new to me. I tried running it in a Javascript for Automation action, which gave me:
{\rtf1\ansi\ansicpg1252\cocoartf2709
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
\pard\tx0\tx1120\tx2240\tx3360\tx4480\tx5600\tx6720\tx7840\tx8960\tx10080\tx11200\tx12320\tx13440\tx14560\tx15680\tx16800\tx17920\tx19040\tx20160\tx21280\tx22400\tx23520\tx24640\tx25760\tx26880\tx28000\tx29120\tx30240\tx31360\tx32480\tx33600\tx34720\pardirnatural
\f0\fs28\fsmilli14182 \cf2 Mamma just killed a man that's terrible! \
Put a gun against his head why?! \
Pulled my trigger makes sense I suppose... \
Now he's dead hello officer, I'd like to report a murder}
So, unless I've missed the point... I'd have to find a way to format the input similarly (arbitrary spaces and // pairs at line ends) and insert it into the javascript at the appropriate point. Is that right?
{{
tf1ansiansicpg1252\cocoartf2709
\cocoatextscaling0\cocoaplatform0{{onttbl0nilcharset0 Menlo-Regular;}}
{{\colortbl;
ed255\green255lue255;
ed0\green0lue0;}}
{{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}}
\pard x0 x1120 x2240 x3360 x4480 x5600 x6720 x7840 x8960 x10080 x11200 x12320 x13440 x14560 x15680 x16800 x17920 x19040 x20160 x21280 x22400 x23520 x24640 x25760 x26880 x28000 x29120 x30240 x31360 x32480 x33600\pardirnatural
0s28smilli14182 \cf2 Mamma just killed a man that's terrible! \
Put a gun against his head why?! \
Pulled my trigger makes sense I suppose... \
Now he's dead hello officer, I'd like to report a murder}
If you run the following macro with the Display Local__Text and Cancel Macro group enabled, you'll get the text input correctly formatted for use in the Javascript:
If you copy and paste this into the green Set public.rtf Pasteboard (Paste Displayed Text) action at <REPLACE THIS>, the pasteboard is correctly set and the tab-aligned text can be pasted. Great!
My suspicion was that each instance of \ in Local__Text might need to be escaped, so I tried adjusting this in the text formatting shell script, but the result was identical. I also tried changing it to single \ characters and \n, but that didn't help either.
For some reason, the clipboard needs to be trimmed for whitespace, as the first line contains 4 leading spaces. I suspect this may be something to do with the \\par function. Nonentheless, I can't envision too many scenarios where trimming whitespace would cause a problem.
The problem now is that writing the clipboard to a file results in completely misaligned result.