There is probably a more Maestronic way of doing this, but FWIW here is a macro which sorts text lines in the clipboard (case-insensitive). If you fire it again it sorts Z-A, toggling each time.
I had done quite a bit of research, and did not see a clear “winner”.
A lot of posters at stackoverflow don’t seem to like the Array.sort() function.
But maybe that is for large, long lists.
On the typical scales of the scripting context (smallish numbers of users per coder, and modest-sized datasets), coder time is much more scarce and valuable than run-time.
(Browser competition means that JavaScript engines are pretty heavily optimised, well beyond what casual scripting really needs, on the whole)
The examples are in ES6 JS, if you are running a pre-Sierra system you can obtain the ES5 equivalent by pasting the ES6 code into the left-hand panel at:
I’ve added ES5 source there now, and also included, with a couple of examples a mappendOrdering function, which makes it easier to write secondary (+) sorts like ‘by descending length and then AZ’
Can someone kindly share with me a version of the script that doesn't have the sort toggle option? It's driving me nuts! I just need it to sort in ascending order.
(() => {
'use strict';
// Rob Trew 2020
ObjC.import('AppKit');
const main = () =>
either(msg => msg)(copyText)(
bindLR(clipTextLR())(
compose(
Right,
unlines,
sortBy(
a => b => a.localeCompare(b)
),
lines
)
)
);
// ----------------------- JXA -----------------------
// clipTextLR :: () -> Either String String
const clipTextLR = () => {
const
v = ObjC.unwrap($.NSPasteboard.generalPasteboard
.stringForType($.NSPasteboardTypeString));
return Boolean(v) && v.length > 0 ? (
Right(v)
) : Left('No utf8-plain-text found in clipboard.');
};
// copyText :: String -> IO String
const copyText = s => {
// String copied to general pasteboard.
const pb = $.NSPasteboard.generalPasteboard;
return (
pb.clearContents,
pb.setStringForType(
$(s),
$.NSPasteboardTypeString
),
s
);
};
// --------------------- GENERIC ----------------------
// https://github.com/RobTrew/prelude-jxa
// Left :: a -> Either a b
const Left = x => ({
type: 'Either',
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: 'Either',
Right: x
});
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = m =>
mf => undefined !== m.Left ? (
m
) : mf(m.Right);
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
fr => e => 'Either' === e.type ? (
undefined !== e.Left ? (
fl(e.Left)
) : fr(e.Right)
) : undefined;
// lines :: String -> [String]
const lines = s =>
// A list of strings derived from a single
// newline-delimited string.
0 < s.length ? (
s.split(/[\r\n]/)
) : [];
// sortBy :: (a -> a -> Ordering) -> [a] -> [a]
const sortBy = f =>
xs => xs.slice()
.sort((a, b) => f(a)(b));
// unlines :: [String] -> String
const unlines = xs =>
// A single string formed by the intercalation
// of a list of strings with the newline character.
xs.join('\n');
// MAIN ---
return main();
})();
In order for me to understand what I'm looking at in your first screenshot, I would like you to run the following action when your clipboard contains the data you are trying to process.
Then paste the result in this thread. You see, I can't really tell what you are dealing with in your first image. If you do the above, it will tell me byte for byte what your input contains. I'm concerned that your input isn't really hyperlinks, just highlighted text.
It says right at the top of your window that you are still using the action called "Javascript for Automation" rather than "Execute Shell Script." I recommend that you try again. I'm likely to be gone for the rest of the day, so someone else may have to help.