(() => {
'use strict';
// main :: IO ()
const main = () => {
const
tocString = Application('Keyboard Maestro Engine')
.getvariable('tocString');
return sortBy(
comparing(x => x[0])
)(
tocString.split(/[\n\r]+/)
.map(entry => {
// Split on any white space, except at the end.
const parts = entry.trim().split(/\s+/);
// The phrase :: the remaining
// parts, delimited by single spaces.
const phrase = parts.slice(1).join(' ');
// The index :: first token,
// without any trailing dot.
const index = parts[0].split('.')[0];
return (`${phrase}\t${index}`);
})
)
.join('\n');
}
// --------------------- GENERIC ---------------------
// comparing :: (a -> b) -> (a -> a -> Ordering)
const comparing = f =>
x => y => {
const
a = f(x),
b = f(y);
return a < b ? -1 : (a > b ? 1 : 0);
};
// list :: StringOrArrayLike b => b -> [a]
const list = xs =>
// xs itself, if it is an Array,
// or an Array derived from xs.
Array.isArray(xs) ? (
xs
) : Array.from(xs || []);
// sortBy :: (a -> a -> Ordering) -> [a] -> [a]
const sortBy = f =>
xs => list(xs).slice()
.sort((a, b) => f(a)(b));
return main();
})();
@ronald, I moved your post to a new topic since it is a new question.
You don't really need RegEx for this.
Here is some simple pseudo code to outline the Actions:
Initialize a KM Variable "Local__LineNum" to 0
Use the KM For Each action with a lines collection in a KM Variable, I'll call "Local__SourceStr", and a loop variable "Local__Line".
In the For Each loop
Increment a counter "Local__LineNum" by 1
append a new Variable "Local__SourceWithLineNumbers" to %Local__Line% %Local__LineNum%
This is NOT everything you need, but should give you the general idea for a solution.
I don’t know where the text is when you start, but if it’s on the clipboard, a shell script of
pbpaste | perl -nle 'print "$_ $."' | pbcopy
will replace the unnumbered text with numbered text on the clipboard. If you expect to have a trailing linefeed at the end of the text and you don’t want that last blank “line” numbered, change the script to this:
@ronald, this is SO EASY just using native, non-scripting, KM Actions, that I feel compelled to provide for all KM users, whom I think most of are more comfortable with non-scripting solutions.
Shell scripts can be very powerful, but also very dangerous if you don't know what you are doing, or how to understand and use scripts provided by others. So I always recommend a KM solution unless there is a compelling reason to use a script.
Example Output
Below is just an example written in response to your request. You will need to use as an example and/or change to meet your workflow automation needs.
I read about pbpaste but it's still not clear as to what it is doing.
When you say pasteboard, do you mean clipboard ?
Let's assume that I start off by selecting the text
Do I have to copy the text to the clipboard before running the shell script ?. Will the output of the script automatically paste, or should I add a paste action ?
Since I was a bit harsh on shell scripts above, let me now say that, IMO, there are a few use cases where a simple, canned, shell script can be the best solution. I have this one saved in my KMFAM collection, and it seems to work fine here:
If any of you shell script gurus care to comment or jump in, please do.
I would expect, but have not tested, that a simple shell script like this would be faster can calling a BBEdit Text Factory, but I could be wrong.
Yes. The two terms are used interchangeably. I believe Keyboard Maestro uses clipboard but Apple (at least for pbpaste and pbcopy uses ‘pasteboard’).
Yes. pbpaste translates to “take what is on the clipboard/pasteboard and send it to output” so whatever you want to work on must already be on it.
You would need to tell the Keyboard Maestro “Execute Shell Script” action to "paste results” (or save results to a variable, or whatever else is suitable).
Note that, as Peter rightly pointed out, my solution only works for fewer than 10 lines.
If you want a simple shell-based solution, instead of mine, you should use Dr Drang’s suggestion.
Note that his uses pbcopy at the end which means “Save the result to the clipboard/pasteboard” so you would not have to tell Keyboard Maestro to do that.
Following up @tjluoma's comment, the reason I have pbpaste and pbcopy in my script is that I was sitting in front of an iPad when I wrote the answer and forgot that Keyboard Maestro has options for dealing with the clipboard as input and output. This would be the better way:
You could, of course, surround this step with Copy and Paste actions to get a macro that replaces the selected text with the line-numbered version of it.
@JMichaelTX brings up an interesting point. In fact he opens a pandora's box, which is to use the simplest fastest tool for the task. In this case it is a one word shell script inside a KBM action.
For a novice, shell scripts are cryptic even though I went so far as to read the take control book on the subject.
In the example below @JMichaelTX uses a one word text transform shell script where I was struggling trying to figure out a regex.
Just as a start, I was wondering where I could find a repertory of very short shell scripts used for the many possible commonly used transformations of selected text. Just a few examples are adding quotes, title care, remove new line feed, remove blank lines, delete tabs, etc etc etc