How to export the results list for the "See also & Classify" command

Ask whenever you want. If you ask now I could change it and you could directly try the changed script :slight_smile:

The second was just a quote of the real script.

1 Like

Ok, first of all, I think some “register” need to be reset before, run it.

If you see in my picture, the original name is “Em que perseveras”

But, in the first line of the new document shows:

See Also Suggestion list “Compromisso pessoal” >> It is another file

Second, should be nice, to create a new group and save these results there.

I think should be easy to localize.

E.g.

Original group: V5AA

See also results: V5AA\seealsoresults\

Hmm, don’t know what happened there. I’ll check.

I see in your picture that you’ve replicated the records in this group.

Because records are replicated I’m afraid it’s not possible to make sure that the script always “finds” the right group (e.g. group “V5AA”) to create the subgroup in as there’s no way to decide which parent group is the right one.

If you always use the script in a window in which you’ve selected the group in the sidebar then it’s possible to use the window’s root group instead of a selected record’s parent group. This way it would be possible to make sure to always create a subgroup in the right group. But you would have to make sure to always use it in a window like the one in picture …

I think it’s easier to use if you manually create one group which could then be used by the script to create subgroups in. You could then move or replicate those subgroups manually.

What do you think?

1 Like

The idea is great.

In fact, if the group to created in the inbox for me is already enough.

In the future, I will create a new database, with only the SeeAlso results and I will certainly move those results there.

Another thing that I intend to do later on is to combine database.

For example:

The DB003 database is only for texts by an author.
The DB002 database is only for authors who comment on this author’s texts.
The BD006 database is only for stories for children. They are folk tales from all over the world that I gathered and I would like to use them to illustrate and correlate the connections.

So, When I select one subject, SEE ALSO LIST bring me a suggestion of:

a) what my favorite author sad about that
b) another authors suggestions
c) a list of folclore stories to read and use with them

1 Like

This was wrong, it of course makes no difference…

So where do you want to create the output groups? And how should they be named?

Do you mean “V5AA/seealsoresults/”, so that the subgroup name is only “seealsoresults”?

Or should the group’s name be also in the subgroup’s name, e.g. “V5AA - seealsoresults”?

This one creates the output groups in parent 1 of the selected record. Remember:

I’ve added this part

-- choose how your output groups should be named. deactivate a line by adding a # at the beginning
			
set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & " - " & "seealsoresults", "/", "\\/") --> "Groupname - seealsoresults"
#set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & "\\" & "seealsoresults" & "\\", "/", "\\/") --> "Groupname\seealsoresults\"
#set theOutputGroup to create location (location of thisRecord) & my replace_String("seealsoresults", "/", "\\/") --> "seealsoresults"

so you can try different names for the output groups.

And I’ve fixed the wrong name in the output record.

-- Create Markdown See Also Suggestion List 

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property maxSeeAlsoResults : 20
property removeSuffix : true -- remove suffix of suggested records
property includeParagraphs : true -- fetch the "first" and "last" paragraph. which paragraphs should act as "first" and "last" can be set below 
property skipMarkdownHeading : true -- skip the first non-blank line if it begins with # (independent of property firstParagraphOffset)

property firstParagraphOffset : 1 -- index of the paragraph which should act as the first. starting at 1. only lines which contain at least one word are counted in (independent of property addEmptyLines)
property lastParagraphOffset : 1 -- index of the paragraph which should act as the last. starting at 1. second last would be 2 (and so on)
property theParagraphPlaceholder : "<span style=\"color: red\">Here's something to do!</span>" -- this is used if a paragraph couldn't be fetched, e.g. when property firstParagraphOffset > count of paragraphs. change to your liking
property maxCharacterCount : 100000 -- skip fetching paragraphs of records whose character count is higher. for skipped paragraphs the placeholder is used. add these paragraphs manually afterwards by clicking the suggestion's name

property removeSelectedRecordSuffix : true -- remove suffix of selected record's name for usage in output record's name and heading
property openOutputRecord : true -- only available if one record is selected
property excludeFromSeeAlso : true -- exclude output record from see also
property excludeFromSearch : false -- exclude output record from search

tell application id "DNtp"
	try
		set theRecords to selection of think window 1
		if theRecords = {} then error "Please select some records"
		set theDatabases to databases
		
		show progress indicator "Creating See Also Suggestions List... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set thisRecordName to name of thisRecord
			step progress indicator thisRecordName
			set theContent to plain text of thisRecord
			set theSeeAlsoResults_record to {}
			
			repeat with thisDatabase in theDatabases
				set theSeeAlsoResults to compare content theContent to thisDatabase
				repeat with thisResult in theSeeAlsoResults
					set theName to name of thisResult as string
					if removeSuffix = true then set theName to my recordName(theName, filename of thisResult)
					set theName to ("[" & theName & "](" & (reference URL of thisResult) & ")") as string
					if includeParagraphs = true then
						set theCharacterCount to (character count of thisResult)
						if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount, text_:(plain text of thisResult)}
						else
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount}
						end if
					else
						set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:0}
					end if
				end repeat
			end repeat
			
			set theSeeAlsoResults_record_sorted to my sort(theSeeAlsoResults_record)
			if (count theSeeAlsoResults_record_sorted) > maxSeeAlsoResults then set theSeeAlsoResults_record_sorted to (items 1 thru maxSeeAlsoResults in theSeeAlsoResults_record_sorted)
			set theMarkdownText_list to {"<style> a {text-decoration: none;} </style>" & linefeed}
			
			repeat with thisResult in theSeeAlsoResults_record_sorted
				if includeParagraphs = true then
					set theCharacterCount to charactercount_ of thisResult
					if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
						set theText to text_ of thisResult
						set theParagraphs to paragraphs of theText
						set theParagraphs_cleaned to {}
						repeat with thisParagraph in theParagraphs
							if words in thisParagraph as string > 0 then set end of theParagraphs_cleaned to thisParagraph as string
						end repeat
						if skipMarkdownHeading = true and (item 1 of theParagraphs_cleaned starts with "#") then set theParagraphs_cleaned to (items 2 thru -1 in theParagraphs_cleaned)
						try
							set firstParagraph to item firstParagraphOffset of theParagraphs_cleaned
						on error
							set firstParagraph to theParagraphPlaceholder
						end try
						try
							set lastParagraph to item -lastParagraphOffset of theParagraphs_cleaned
						on error
							set lastParagraph to theParagraphPlaceholder
						end try
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & firstParagraph & space & space & linefeed & lastParagraph & space & space & linefeed
					else if theCharacterCount > 0 and theCharacterCount > maxCharacterCount then
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed
					end if
				else
					set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed
				end if
			end repeat
			
			set theMarkdownText to my tid(theMarkdownText_list, linefeed)
			if removeSelectedRecordSuffix = true then set thisRecordName to my recordName(thisRecordName, filename of thisRecord)
			
			-- choose how your output groups should be named. deactivate a line by adding a # at the beginning
			
			set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & " - " & "seealsoresults", "/", "\\/") --> "Groupname - seealsoresults"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & "\\" & "seealsoresults" & "\\", "/", "\\/") --> "Groupname\seealsoresults\"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String("seealsoresults", "/", "\\/") --> "seealsoresults"
			
			set theSeeAlsoListRecord to create record with {name:"See Also Suggestion List - " & "\"" & thisRecordName & "\"", type:markdown, plain text:("### See Also Suggestion List " & "[" & thisRecordName & "](" & (reference URL of thisRecord) as string) & ")" & linefeed & linefeed & theMarkdownText, exclude from see also:excludeFromSeeAlso, exclude from search:excludeFromSearch} in theOutputGroup
			
		end repeat
		hide progress indicator
		
		if openOutputRecord = true and (count theRecords) = 1 then
			open window for record theSeeAlsoListRecord
			activate
		end if
		
	on error error_message number error_number
		hide progress indicator
		activate
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix

on sort(theList)
	set anArray to current application's NSArray's arrayWithArray:theList
	set theDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"score_" ascending:false selector:"compare:"
	set newList to (anArray's sortedArrayUsingDescriptors:{theDesc}) as list
end sort

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theString to theList as text
	set AppleScript's text item delimiters to d
	return theString
end tid

on replace_String(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replace_String
1 Like

It is perfect!!!

Many, many thanks @pete31

1 Like

Hi,

This topic was very useful for my project.

From now, I have one more question:

Is it possible to add the second paragraph for this macro?

This is an example of my wish for see also results:

First paragraph (as I told before is a citation)
Second Paragraph (This is the introduction. Now I feel it is important to understand about the hole text)
Last paragraph (Reference)

:slight_smile:

Property firstParagraphsCount lets you choose how many lines should be included.

-- Create Markdown See Also Suggestion List 

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property maxSeeAlsoResults : 20
property removeSuffix : true -- remove suffix of suggested records
property includeParagraphs : true -- fetch the "first" and "last" paragraph. which paragraphs should act as "first" and "last" can be set below 
property skipMarkdownHeading : true -- skip the first non-blank line if it begins with # (independent of property firstParagraphOffset)

property firstParagraphOffset : 1 -- index of the paragraph which should act as the first. starting at 1. only lines which contain at least one word are counted in (independent of property addEmptyLines)
property firstParagraphsCount : 2 -- count of included paragraphs  
property lastParagraphOffset : 1 -- index of the paragraph which should act as the last. starting at 1. second last would be 2 (and so on)
property theParagraphPlaceholder : "<span style=\"color: red\">Here's something to do!</span>" -- this is used if a paragraph couldn't be fetched, e.g. when property firstParagraphOffset > count of paragraphs. change to your liking
property maxCharacterCount : 100000 -- skip fetching paragraphs of records whose character count is higher. for skipped paragraphs the placeholder is used. add these paragraphs manually afterwards by clicking the suggestion's name

property removeSelectedRecordSuffix : true -- remove suffix of selected record's name for usage in output record's name and heading
property openOutputRecord : true -- only available if one record is selected
property excludeFromSeeAlso : true -- exclude output record from see also
property excludeFromSearch : false -- exclude output record from search

tell application id "DNtp"
	try
		set theRecords to selection of think window 1
		if theRecords = {} then error "Please select some records"
		set theDatabases to databases
		
		show progress indicator "Creating See Also Suggestions List... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set thisRecordName to name of thisRecord
			step progress indicator thisRecordName
			set theContent to plain text of thisRecord
			set theSeeAlsoResults_record to {}
			
			repeat with thisDatabase in theDatabases
				set theSeeAlsoResults to compare content theContent to thisDatabase
				repeat with thisResult in theSeeAlsoResults
					set theName to name of thisResult as string
					if removeSuffix = true then set theName to my recordName(theName, filename of thisResult)
					set theName to ("[" & theName & "](" & (reference URL of thisResult) & ")") as string
					if includeParagraphs = true then
						set theCharacterCount to (character count of thisResult)
						if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount, text_:(plain text of thisResult)}
						else
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount}
						end if
					else
						set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:0}
					end if
				end repeat
			end repeat
			
			set theSeeAlsoResults_record_sorted to my sort(theSeeAlsoResults_record)
			if (count theSeeAlsoResults_record_sorted) > maxSeeAlsoResults then set theSeeAlsoResults_record_sorted to (items 1 thru maxSeeAlsoResults in theSeeAlsoResults_record_sorted)
			set theMarkdownText_list to {"<style> a {text-decoration: none;} </style>" & linefeed}
			
			repeat with thisResult in theSeeAlsoResults_record_sorted
				if includeParagraphs = true then
					set theCharacterCount to charactercount_ of thisResult
					if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
						set theText to text_ of thisResult
						set theParagraphs to paragraphs of theText
						set theParagraphs_cleaned to {}
						repeat with thisParagraph in theParagraphs
							if words in thisParagraph as string > 0 then set end of theParagraphs_cleaned to thisParagraph as string
						end repeat
						if skipMarkdownHeading = true and (item 1 of theParagraphs_cleaned starts with "#") then set theParagraphs_cleaned to (items 2 thru -1 in theParagraphs_cleaned)
						try
							set firstParagraphs_list to items firstParagraphOffset thru ((firstParagraphOffset + firstParagraphsCount) - 1) of theParagraphs_cleaned
							set firstParagraphs_list_clean to {}
							repeat with thisParagraph in firstParagraphs_list
								set thisParagraph to thisParagraph as string
								if thisParagraph starts with "*" then set thisParagraph to ("\\*" & characters 2 thru -1 in thisParagraph) as string
								set end of firstParagraphs_list_clean to thisParagraph
							end repeat
							set firstParagraphs to my tid(firstParagraphs_list_clean, linefeed)
						on error
							set firstParagraphs to theParagraphPlaceholder
						end try
						try
							set lastParagraph to (item -lastParagraphOffset of theParagraphs_cleaned)
							if lastParagraph starts with "*" then set lastParagraph to ("\\*" & characters 2 thru -1 in lastParagraph) as string
						on error
							set lastParagraph to theParagraphPlaceholder
						end try
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & firstParagraphs & space & space & linefeed & lastParagraph & space & space & linefeed
					else if theCharacterCount > 0 and theCharacterCount > maxCharacterCount then
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed
					end if
				else
					set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed
				end if
			end repeat
			
			set theMarkdownText to my tid(theMarkdownText_list, linefeed)
			if removeSelectedRecordSuffix = true then set thisRecordName to my recordName(thisRecordName, filename of thisRecord)
			
			-- choose how your output groups should be named. deactivate a line by adding a # at the beginning
			
			set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & " - " & "seealsoresults", "/", "\\/") --> "Groupname - seealsoresults"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & "\\" & "seealsoresults" & "\\", "/", "\\/") --> "Groupname\seealsoresults\"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String("seealsoresults", "/", "\\/") --> "seealsoresults"
			
			set theSeeAlsoListRecord to create record with {name:"See Also Suggestion List - " & "\"" & thisRecordName & "\"", type:markdown, plain text:("### See Also Suggestion List " & "[" & thisRecordName & "](" & (reference URL of thisRecord) as string) & ")" & linefeed & linefeed & theMarkdownText, exclude from see also:excludeFromSeeAlso, exclude from search:excludeFromSearch} in theOutputGroup
			
		end repeat
		hide progress indicator
		
		if openOutputRecord = true and (count theRecords) = 1 then
			open window for record theSeeAlsoListRecord
			activate
		end if
		
	on error error_message number error_number
		hide progress indicator
		activate
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix

on sort(theList)
	set anArray to current application's NSArray's arrayWithArray:theList
	set theDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"score_" ascending:false selector:"compare:"
	set newList to (anArray's sortedArrayUsingDescriptors:{theDesc}) as list
end sort

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

on replace_String(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replace_String
1 Like

almost perfect.

Just need an enter between paragraphs. Is it possible?

In markdown you have to use & space & space at the end of a line to separate it from the next one.

This should do it

-- Create Markdown See Also Suggestion List 

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property maxSeeAlsoResults : 20
property removeSuffix : true -- remove suffix of suggested records
property includeParagraphs : true -- fetch the "first" and "last" paragraph. which paragraphs should act as "first" and "last" can be set below 
property skipMarkdownHeading : true -- skip the first non-blank line if it begins with # (independent of property firstParagraphOffset)

property firstParagraphOffset : 1 -- index of the paragraph which should act as the first. starting at 1. only lines which contain at least one word are counted in (independent of property addEmptyLines)
property firstParagraphsCount : 2 -- count of included paragraphs  
property lastParagraphOffset : 1 -- index of the paragraph which should act as the last. starting at 1. second last would be 2 (and so on)
property theParagraphPlaceholder : "<span style=\"color: red\">Here's something to do!</span>" -- this is used if a paragraph couldn't be fetched, e.g. when property firstParagraphOffset > count of paragraphs. change to your liking
property maxCharacterCount : 100000 -- skip fetching paragraphs of records whose character count is higher. for skipped paragraphs the placeholder is used. add these paragraphs manually afterwards by clicking the suggestion's name

property removeSelectedRecordSuffix : true -- remove suffix of selected record's name for usage in output record's name and heading
property openOutputRecord : true -- only available if one record is selected
property excludeFromSeeAlso : true -- exclude output record from see also
property excludeFromSearch : false -- exclude output record from search

tell application id "DNtp"
	try
		set theRecords to selection of think window 1
		if theRecords = {} then error "Please select some records"
		set theDatabases to databases
		
		show progress indicator "Creating See Also Suggestions List... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set thisRecordName to name of thisRecord
			step progress indicator thisRecordName
			set theContent to plain text of thisRecord
			set theSeeAlsoResults_record to {}
			
			repeat with thisDatabase in theDatabases
				set theSeeAlsoResults to compare content theContent to thisDatabase
				repeat with thisResult in theSeeAlsoResults
					set theName to name of thisResult as string
					if removeSuffix = true then set theName to my recordName(theName, filename of thisResult)
					set theName to ("[" & theName & "](" & (reference URL of thisResult) & ")") as string
					if includeParagraphs = true then
						set theCharacterCount to (character count of thisResult)
						if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount, text_:(plain text of thisResult)}
						else
							set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:theCharacterCount}
						end if
					else
						set end of theSeeAlsoResults_record to {name_:theName, score_:(score of thisResult), charactercount_:0}
					end if
				end repeat
			end repeat
			
			set theSeeAlsoResults_record_sorted to my sort(theSeeAlsoResults_record)
			if (count theSeeAlsoResults_record_sorted) > maxSeeAlsoResults then set theSeeAlsoResults_record_sorted to (items 1 thru maxSeeAlsoResults in theSeeAlsoResults_record_sorted)
			set theMarkdownText_list to {"<style> a {text-decoration: none;} </style>" & linefeed}
			
			repeat with thisResult in theSeeAlsoResults_record_sorted
				if includeParagraphs = true then
					set theCharacterCount to charactercount_ of thisResult
					if theCharacterCount > 0 and theCharacterCount ≤ maxCharacterCount then
						set theText to text_ of thisResult
						set theParagraphs to paragraphs of theText
						set theParagraphs_cleaned to {}
						repeat with thisParagraph in theParagraphs
							if words in thisParagraph as string > 0 then set end of theParagraphs_cleaned to thisParagraph as string
						end repeat
						if skipMarkdownHeading = true and (item 1 of theParagraphs_cleaned starts with "#") then set theParagraphs_cleaned to (items 2 thru -1 in theParagraphs_cleaned)
						try
							set firstParagraphs_list to items firstParagraphOffset thru ((firstParagraphOffset + firstParagraphsCount) - 1) of theParagraphs_cleaned
							set firstParagraphs_list_clean to {}
							repeat with thisParagraph in firstParagraphs_list
								set thisParagraph to thisParagraph as string
								if thisParagraph starts with "*" then set thisParagraph to ("\\*" & characters 2 thru -1 in thisParagraph) as string
								set end of firstParagraphs_list_clean to thisParagraph & space & space
							end repeat
							set firstParagraphs to my tid(firstParagraphs_list_clean, linefeed)
						on error
							set firstParagraphs to theParagraphPlaceholder
						end try
						try
							set lastParagraph to (item -lastParagraphOffset of theParagraphs_cleaned) & space & space
							if lastParagraph starts with "*" then set lastParagraph to ("\\*" & characters 2 thru -1 in lastParagraph) as string
						on error
							set lastParagraph to theParagraphPlaceholder
						end try
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & firstParagraphs & space & space & linefeed & lastParagraph & space & space & linefeed
					else if theCharacterCount > 0 and theCharacterCount > maxCharacterCount then
						set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed & theParagraphPlaceholder & space & space & linefeed
					end if
				else
					set end of theMarkdownText_list to "* " & name_ of thisResult & space & space & linefeed
				end if
			end repeat
			
			set theMarkdownText to my tid(theMarkdownText_list, linefeed)
			if removeSelectedRecordSuffix = true then set thisRecordName to my recordName(thisRecordName, filename of thisRecord)
			
			-- choose how your output groups should be named. deactivate a line by adding a # at the beginning
			
			set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & " - " & "seealsoresults", "/", "\\/") --> "Groupname - seealsoresults"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String((name of parent 1 of thisRecord) & "\\" & "seealsoresults" & "\\", "/", "\\/") --> "Groupname\seealsoresults\"
			#set theOutputGroup to create location (location of thisRecord) & my replace_String("seealsoresults", "/", "\\/") --> "seealsoresults"
			
			set theSeeAlsoListRecord to create record with {name:"See Also Suggestion List - " & "\"" & thisRecordName & "\"", type:markdown, plain text:("### See Also Suggestion List " & "[" & thisRecordName & "](" & (reference URL of thisRecord) as string) & ")" & linefeed & linefeed & theMarkdownText, exclude from see also:excludeFromSeeAlso, exclude from search:excludeFromSearch} in theOutputGroup
			
		end repeat
		hide progress indicator
		
		if openOutputRecord = true and (count theRecords) = 1 then
			open window for record theSeeAlsoListRecord
			activate
		end if
		
	on error error_message number error_number
		hide progress indicator
		activate
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix

on sort(theList)
	set anArray to current application's NSArray's arrayWithArray:theList
	set theDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"score_" ascending:false selector:"compare:"
	set newList to (anArray's sortedArrayUsingDescriptors:{theDesc}) as list
end sort

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

on replace_String(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replace_String
1 Like

wonderful!!!

Is it perfect!

Many, many, thanks again, @pete31 to improve my job!

1 Like

From another thread in which I was trying to adapt the output of this script:

The notes in question tend to look like this:

Why do > symbols cause a fault, and how would I fix it?

The scripts in this thread do not escape Markdown characters (yet).


By escaping (i.e. prefixing) Markdown characters with a \

Thank you @pete31 . This script will help me alot in my work. I’ve two requests. 1. Can we add URL to each record in the md file? 2. I want to learn scripting. Can you guide me how can I learn it? How long does it normally take? I’ve been shying away from learning scripting and losing my productivity. Thank you.

The time to learn something depends on a lot of factors

  • previous knowledge
  • effort put into learning
  • difficulty of the subject (steep leaving curve?), which is related to the first point

If you know a programming language, learning another one is imo not big deal.

Personally, I’d discourage newbies to invest time in learning ApppleScript and advise to go with JavaScript. Others (probably including @pete31) would argue for ApppleScript because of a perceived ease of learning.

The main advantage of AppleScript is IMHO that it’s still much more reliable than JXA which has all kinds of shortcomings & bugs (and DEVONthink 3 includes almost a dozen of workarounds already to make it more reliable). But it’s definitely better for data/string processing.

1 Like

Not to mention Array methods like filter, map, and forEach, data types like Set and the availability of objects as well as introspection (missing from JXA, though). And constant development – ECMA is working on JavaScript, Apple is doing nothing with AppleScript.
But as with all programming languages (and code editors), it’s largely a matter of preference. Every problem can be solved in every language – it’s just a matter of time and effort.

And it’s even possible to mix them, see for example: