How to run a simple Regex on the copied text?

Hi and good day,
When copying text the paragraph margins ( p or div in HTML) disappear, so the text is more difficult to read.
see:

How could one run a simple Regex on the copied text?

such as:

Replace /n with /n/n

in an Applescript?!?

/
Any assistance would be greatly appreciated!

With best regards,
Omar KN

Without scripting, you can’t run a RegEx on it.
Do an Edit > Find > Find and enter Option-Return in the Find field and Option-Return twice in the Replace field.

This works, thank you.

However, a script would be more convenient.

Would it be a good idea to connect to the Devonthink people for a new script?

/

with best regards, Omar KN, Stockholm, Sweden

If you just want to obtain a text record like:

from a web-pasted source like:

Then a regular expression may be more trouble than its worth (they often are).

It may be enough, if I’ve understood the context, to just add an extra linefeed at the end of each para, in this kind of pattern:

either(msg => msg)(copyText)(
    bindLR(clipTextLR())(
        compose(
            Right,
            unlines,
            map(s => s + '\n'),
            lines
        )
    )
);
Full JavaScript for Automation Source
(() => {
    'use strict';

    // Rob Trew 2020

    ObjC.import('AppKit');

    const main = () =>
        either(msg => msg)(copyText)(
            bindLR(clipTextLR())(
                compose(
                    Right,
                    unlines,
                    map(s => s + '\n'),
                    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]/)
        ) : [];


    // map :: (a -> b) -> [a] -> [b]
    const map = f =>
        // The list obtained by applying f
        // to each element of xs.
        // (The image of xs under f).
        xs => (
            Array.isArray(xs) ? (
                xs
            ) : xs.split('')
        ).map(f);


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

or in AppleScript, perhaps:

use AppleScript version "2.4"
use scripting additions

on moreSpace(x)
    x & linefeed
end moreSpace


on run
    set the clipboard to unlines(map(moreSpace, ¬
        paragraphs of (the clipboard)))
end run


-------------------- GENERIC FUNCTIONS --------------------
-- https://github.com/RobTrew/prelude-applescript

-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set s to xs as text
    set my text item delimiters to dlm
    s
end unlines

You can use sed. Have a look at the standard regex script how it’s used there.

Edit: and if I’m not mistaken @cgrunenberg is building regular expressions into smartrules.

If I’d had to do it in JavaScript, I’d do this (untested and assuming that the text to be modified is part of a currently selected DT3 document.) Assuming that only \n is used for new lines, not \r or \r\n.

(() => {

app = Application('DEVONthink 3');
app.includeStandardAdditions = true;

var sel = app.selection();
sel.forEach(doc => {
  text = doc.plainText();
  doc.plainText = text.replace(/\n/g,"\n\n");
});
})

While trying to compile it - for the last line, there was the error:

"Expected expression, property or key form, etc. but found end of script.”

Is something missing there?

/

with best regards, Omar KN, Stockholm, Sweden

Full JavaScript for Automation Source

To use a JavaScript for DT3, how to package it (in BBEdit for ex?) and can it be put into the DT3’s Scripts Folder?

/okn

That’s usually just a copy-paste error – the thing that is missing is probably the last line or two.

I’m not yet quite sure what ‘it’ is in this context though … The JS full source ? just the JS main expression ? The AppleScript ?

For the JS full source, click the disclosure triangle in the original post:

For JS, in Script Editor, switch the language selector at top-left to JavaScript, and then save as as .scpt file.

You should then be able to use the JS-compiled .scpt anywhere that you can use an AppleScript-compiled .scpt, including in the DT3 Scripts folder.

Rephrased:

To use a JavaScript for DT3, how to package the JavaScript (in BBEdit for ex?) and can it be put into the DT3’s Scripts Folder?

Just save it in the DT3 script folder from Apple’s script editor. The editor does all the packaging for you.

As can be seen from the screen dump, I put 2 ”Replace -n with -n-n.scpt” (one AppleScript and 1 JScr.) into the folder com.devon-technologies.think3/Menu.

Text in DT3 is selected, when going with the mousse over the script icons nothing happens.

Anything else to do?

/

with best regards, Omar KN, Stockholm, Sweden

What would you expect to happen when you move your mouse over the script icon? Did you CLICK on the icon?

Here is what I do:

See

the text in DT3 is selected, mouse over and release mouse (cannot click it in a context menu) but nothing happens.

The scripts were copied as is.

/

with best regards, Omar KN, Stockholm, Sweden

The script I posted works on the selected document(s), not the clipboard.

So now I selected a document → name turns blue → go over the script with mouse → nothing happens .

/okn

I don’t quite get it. The script menu is not a context menu, AFAIK. So what I do is:

  • select a file in DT3
  • click on the script icon in the menu bar
  • move the mouse to “Rename”
  • a submenu opens
  • I select the script I want (it becomes blue)
  • AND THEN I CLICK on it.

If I don’t click, nothing happens. Even if it where a context menu, which it isn’t, I’d still have to click on the selected entry to execute the command. How else would DT3 (or any app, for that matter) know when you want to execute a command and when you simply want to move the mouse?

It’s enough to just move over the script and release the mouse, please view the video:

There must be some other problem, both scripts could be compiled.

Hopefully we can find the cause of its malfunction.

/okn