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.
(() => {
'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();
})();
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
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");
});
})
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.
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?