Coming a bit late to the party, but here’s a version in JavaScript:
(() => {
const app = Application("DEVONthink 3");
/* get all MD records from current selection */
const records = app.selectedRecords.whose({ _match: [ObjectSpecifier().type, "markdown"] })();
/* Loop over records */
records.forEach(r => {
/* Split plaintext in paragraphs */
const txtArray = r.plainText().split("\n");
const newText = [];
let heading = "";
/* Loop over paragraphs */
txtArray.forEach(txt => {
/* Check for level 2 heading */
let isHeading = txt.match(/^##\s+(.*)/);
/* Check for bullet list block */
let isList = txt.match(/^\*\s+(.*)/);
if (isHeading) {
/* Save heading text in temp variable */
heading = isHeading[1];
} else if (isList) {
/* save new paragraph:
Bullet list block without the bullet and
corresponding heading appended in parenthesis
*/
newText.push(`${isList[1]} (${heading})`)
} else {
/* If neither bullet nor heading, save the paragraph as is */
newText.push(txt);
}
})
r.plainText = newText.join('\n');
})
})()
If someone needs not the heading but only a part of it, this should be done in the if (isHeading) part. Just set heading to whatever you want to appear in the parenthesis after the (ex-)bullet blocks.
I managed to solve this both in Apple Script and Javascript.
Now I get the Heading 1 in the parentheses.
This is the Applescript version:
on performSmartRule(theRecords)
tell application id "DNtp"
repeat with theRecord in theRecords
if (type of theRecord as string) = "markdown" then
-- Only process Markdown docs
set newText to {}
-- Set up an empty list to push the paragraphs into)
set currentText to (plain text of theRecord)
-- Get the current text of the document
set titleText to (characters 3 thru -1 of paragraph 1 of currentText as string) -- Cache all but the control characters in a variable
repeat with thisLine in (paragraphs of currentText)
-- Loop through the document, paragraph by paragraph
if thisLine begins with "##" then
-- If this is an H2 page link
set cachedText to (characters 4 thru -1 of thisLine as string) -- Cache all but the control characters in a variable
else if thisLine begins with "* " then
-- If it's just a bulleted paragraph
copy ((characters 3 thru -1 of thisLine as string) & " (" & (titleText) & ": " & (cachedText) & ") " & return) to end of newText
-- Get all but the control characters and concatenate the cachedText.
-- Then push it to the newText list
else
copy thisLine & return to end of newText
-- Anything else, including the H1 line at the top, just push into the newText list
end if
end repeat
set plain text of theRecord to (newText as string)
-- Set the text of the document to the new text
end if
end repeat
end tell
end performSmartRule
(() => {
const app = Application("DEVONthink 3");
/* get all MD records from current selection */
const records = app.selectedRecords.whose({ _match: [ObjectSpecifier().type, "markdown"] })();
/* Loop over records */
records.forEach(r => {
/* Split plaintext in paragraphs */
const txtArray = r.plainText().split("\n");
const newText = [];
let heading = "";
let heading1 = "";
txtArray.every(txt => {
/* Loop over paragraphs */
let isHeading1 = txt.match(/^#\s+(.*)/);
if (isHeading1) {
heading1 = isHeading1[1];
return false;
}
return true;
})
txtArray.forEach(txt => {
/* Check for level 2 heading */
let isHeading = txt.match(/^##\s+(.*)/);
/* Check fior bullet list block */
let isList = txt.match(/^\*\s+(.*)/);
if (isHeading) {
/* Save heading text in temp variable */
heading = isHeading[1];
} else if (isList) {
/* save new paragraph:
Bullet list block without the bullet and
corresponding heading appended in parenthesis
*/
newText.push(`${isList[1]} (${heading1}: ${heading})`)
} else {
/* If neither bullet nor heading, save the paragraph as is */
newText.push(txt);
}
})
r.plainText = newText.join('\n');
})
})()
The AppleScript is for use in a smart rule, the JavaScript is not (yet). It’s not too difficult to make it work as script in a smart rule, too.
In the JavaScript, there’s no need for let. unless you modify the variable later on. Otherwise, use const. Also, you seem to have two loops over the same array – why?
If anyone does want to tidy the JS up a little and adapt it for a smart rule, then a comment I might add to @chrillek’s good points is that the idiom:
declare a []
.forEach … .push
may be making life a bit complicated, especially for new users, when you can just define the new array that you want directly, in terms of .map or, even more flexibly: .flatMap, or .reduce