Kick these tires:
Works great. I tried modifying it myself but my JavaScript knowledge is close to nil.
Thank you so much!
You're welcome!
These days, FWIW, | would probably use an option type to define what happens if the clipboard contents isn't textual.
either(msg => msg)(copyText)(
bindLR(clipTextLR())(
compose(
Right,
unlines,
sortBy(
a => b => a.localeCompare(b)
),
lines
)
)
Sort text in clipboard (AZ).kmmacros (21.0 KB)
Full JS source
(() => {
'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();
})();
Hi,
sorry to revive a dead thread, but hoping to avoid making a new one.
Is there a way to edit this such that hyperlinks are maintained?
Not sure I understand the question – you are hoping to sort rich text rather than plain text ?
To give you an answer, I would need so see:
- an example of an input text with hyperlinks of the kind that you have in mind,
- the sorted output that you saw, and
- an example of what you expected.
To give you an answer, I would need so see:
- an example of an input text with hyperlinks of the kind that you have in mind,
- the sorted output that you saw, and
- an example of what you expected.
Here you go!
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.
Then paste the result in this thread. You see, I can't really tell what you are dealing with in your first image.
When I click on the text I get redirected to a website, so I suspect they are hyperlinks. I'll post in a second.
EDIT:
Here is what I get
I'm 99.999% sure that you accidentally used this action:
instead of this action:
Can you see the difference? Can you try again with the correct action?
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.
That's what I thought I would see. The problem is that you want to sort based on the hyperlink, but as you can see from the hex dump, your source data doesn't contain the hyperlink anymore. However you created that text, all you are left with is the "display text." Can you see that there is no hyperlink in there? Therefore it's impossible to sort using the hyperlink data.
I think the next step is to explain where you got your links from, and what you did to post them in your screenshot above. Whatever you did deleted the hyperlink data. Until you get the links, you cannot sort on the links.
My impression is that the OP is:
- Starting with RTF text, and
- (inadvertently) creating a plain text derivative which drops the hyperlink layer
- getting the impression that that loss took place during the plain text sort.
I suppose one alternative might be:
RTF -> Markdown with [Label](URL) links -> Sorted Markdown with those links -> RTF
i.e. what they may effectively be looking for is something like:
RTF -> Markdown
conversion, and
Markdown -> RTF conversion
.
Pandoc ?
Yes! That's why I had him provide the dump. I was planning to come up with a sort mechanism using the markdown syntax you are referring to, once he fixed his input data. But I'll defer to you now.
Go for it !
@reicc, as @ComplexPoint suggested, you could convert your RTF source to Markdown syntax which is possible. I found a post on this forum which explains how to do that:
If you can manage that, and place your text into a variable named MyResult, then the next step would be to sort the lines based on the URL, which would be quite easy, probably using an Execute Shell script roughly this simple.
The above action would sort them by URL. Now the next step depends upon what you want to do. You could either convert the Markdown back to RTF, or if you don't really care about the hyperlink at this point in time, you could just strip it out, probably like this, which gets rid of the text you don't want:
But in summary, you can't sort by URL until the URL is part of your input data, and as the dump showed, you removed the URL in your example. You have to find a way to get that data back. Perhaps if you tell us what you did to strip out the URL, we might see a way to save the URL.
Perhaps, for example, copying from RTF, but then doing something (like assigning to a plain text KM variable) which effectively selects the
public.utf8-plain-text
rather thanpublic.rtf
pasteboard item from those available in the clipboard.
That's exactly what I suspect he did, but we might as well wait to hear it from him.