Script to copy a single line in markdown document.

Hi. I’m a Brazilian musician and music producer. I’m using DT4 for music production management, research, Zettelkasten, writing music theory articles and books, and task management. I have Things 3 and OmniFocus 4, but I want to move my entire workflow to DT4. How to create a script to copy specific lines, ending with #to-do, in a markdown document and export it to a new markdown document? Is this possible?

Welcome @Edu
Can you provide more information on this. It’s not much to go on and automation requires specific details.
Post example Markdown source code that would be scraped and what the resulting document would look like.

Might be. As @bluefrog said, not enough information to go on.

Do you just want to grab lines from a single MD document or from a list? In the latter case, should they all be copied to the same new document or to different ones? A very simple JavaScript script working on a single selected record could look like this:

(() => {
  const app = Application("DEVONthink");
  const record = app.selectedRecords[0];
  const txt = record.plainText();
  const todoText = txt.split("\n").filter(line => line.endsWith('#to-do')).join("\n\n");
  const newRecord = app.createRecordWith({name: 'todos.md', 'record type': 'markdown'});
  newRecord.plainText = todoText;
})()
2 Likes

Dear Jim, thanks for your reply!
Of course!
My idea is to extract lines from an .md file and copy them to a new .md file, like the one I wrote below. The script should copy only the lines that end with #to-do. Another important thing to note is that I intend to use AppleScript for this.

Source document in .md file

Title

  • line 1
  • line 2 #to-do
  • line 3
  • line 4
  • line 5 #to-do

New document in .md file with the copied lines

  • line 2 #to-do
  • line 5 #to-do

Hi Chrillek, thanks for your reply!
Sorry for not providing this information sooner, but I’ll be using AppleScript. If there’s a way to translate the Java script into AppleScript, I’d be happy to try it out!

I appreciate the process to extract tasks from a document (not limited to .md)
My script copies selected text
If editable, I replace the selected text with a link

I find it more useful to copy the lines to separate task notes, tagged with ToDo
I also use tags for Status, Project, DueDate

I used to manage projects this way, @DTLow: each task was a separate document. Your method is excellent for this type of management. However, today I have to work with information and tasks in a single .md document.

I use a different script to generate my daily task list document
Actually a spreadsheet showing the tasks in a gantt timeline view

You’re welcome!
Here is a simple approach that should be fairly easily understood…

tell application id "DNtp"
	if not (exists (content record)) then return
	-- The content record is the currently viewed document.
	set cRecord to content record
	set allText to (plain text of cRecord)
	set allPara to paragraphs of allText
	set theOld to {} -- A new empty list for the non-To-Do lines
	set theNew to {} -- A new empty list for the To-Do lines
	
	repeat with theItem in allPara
		-- theItem is a reference to an item in allPara, e.g., item 3 of every item of… so it needs to be coerced to a string
		set thePara to theItem as string
		
		if thePara ends with "#to-do" then -- Does the line (the string) end with "#to-do"? If so…
			copy (thePara & linefeed) to end of theNew -- Add the line to the list for the new document
		else -- If not…
			copy (thePara & linefeed) to end of theOld -- Add the line to the list for the current document
		end if
	end repeat
	
	if theNew is not {} then -- If the list for the new document isn't empty…
		set newDoc to create record with {name:"ToDo's", type:markdown, content:(theNew as string)} in current group -- Make the document
		set plain text of cRecord to (theOld as string) -- Set the text of the current document to the theOld list without to-do lines.
	end if
end tell

Note this is written in a simple, easy to read format. As your skill in scripting increases, you will find ways to write more succinctly.

Alternative Repeat Method

Here is another option for setting up the repeat loop.

	repeat with incr from 1 to (allPara's length)
		set thePara to (item incr of allPara)
		-- Each item in allPara is already a string in this case so no coercion is needed. 
	
		if thePara ends with "#to-do" then
			copy (thePara & linefeed) to end of theNew
		else
			copy (thePara & linefeed) to end of theOld
		end if
	end repeat

Neither method is correct or incorrect. Both are valid. However, there will be use cases when one method has an advantage over the other.

3 Likes

I also have a slightly more advanced version, if you’d like to see it.
It isn’t terribly hard to understand and employs a method some think “controversial” but it yields a document more like this without a ton more effort…

2 Likes

I know I’d love to see it - I like controversial scripting!

PS is the use of the apostrophe in “To-Do’s” the controversial bit? Because it’s making my eyes twitch! :rofl:

The script worked perfectly!
Of course, I’d love to see the advanced version.
Thank you very much, it will be a great help for our work here!

1 Like

Glad to hear it :slight_smile:

Here is a more advanced version…

tell application id "DNtp"
	if not (exists content record) then return
	set od to AppleScript's text item delimiters
	tell content record
		set {theOld, theNew} to {{}, {}}
		repeat with thePara in (paragraphs of (get plain text))
			if (thePara as string) ends with "#to-do" then
				copy (thePara as string) to end of theNew
			else
				copy (thePara as string) to end of theOld
			end if
		end repeat
		if theNew is not {} then
			set AppleScript's text item delimiters to linefeed
			set newDoc to create record with {name:"ToDo's", type:markdown, content:{"# To-Do's", "---", theNew, "", "---", "*Linked from:* " & my mdLink(name without extension, reference URL)} as string} in (location group of it)
			set plain text to ((text items of theOld) as string)
		end if
	end tell
	set AppleScript's text item delimiters to od
end tell

-- This convenience handler is for the potential of using other links in the document.
on mdLink(recName, recURL)
	return ("[" & recName & "](" & recURL & ")" as string)
end mdLink
2 Likes