Toggle sort text lines in clipboard Aa-Zz ⇄ Zz-Aa

Kick these tires:

Toggle-sort clipboard contents (AZ only).kmmacros (18.7 KB)

2 Likes

Works great. I tried modifying it myself but my JavaScript knowledge is close to nil.

Thank you so much!

You're welcome!

1 Like

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();
})();
3 Likes

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:

  1. an example of an input text with hyperlinks of the kind that you have in mind,
  2. the sorted output that you saw, and
  3. an example of what you expected.

To give you an answer, I would need so see:

  1. an example of an input text with hyperlinks of the kind that you have in mind,
    image
  1. the sorted output that you saw, and
    image
  1. an example of what you expected.
    image

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.

image

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:

image

instead of this action:

image

Can you see the difference? Can you try again with the correct action?

I do, thanks! Here is the 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.

oh sorry I sent the wrong screenshot.

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.

1 Like

My impression is that the OP is:

  1. Starting with RTF text, and
  2. (inadvertently) creating a plain text derivative which drops the hyperlink layer
  3. 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.

1 Like

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.

image

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:

image

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.

@reicc

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 than
  • public.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.

1 Like