This script converts WikiLinks to Markdown links.
WikiLinks in any form
-
Hello World
-
Hello World.md
-
[[Hello World]]
-
[[Hello World.md]]
are converted to item links, depending on property useSuffix
-
[Hello World.md](x-devonthink-item://1EC569F5-5086-49C0-8D5A-F7CB4523F76D)
-
[Hello World](x-devonthink-item://1EC569F5-5086-49C0-8D5A-F7CB4523F76D)
Yes, you can access your wiki in DEVONthink To Go
If you don’t want to convert your original records use duplicates, sync,
Result with useSuffix
set to true
Result with useSuffix
set to false
Note:
Although I assume that the way the script uses regex there’s no chance of replacing wrong strings I might have missed something.
Before usage with real data:
-
Test with duplicates in a new database.
After testing with duplicates:
-
If you first want to see the result of a conversion
-
duplicate the record you want to convert,
-
run the script on the duplicate,
-
verify the result,
-
paste the result into the original record.
-
-- Convert WikiLinks to Markdown links
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
property useSuffix : true -- include suffix in markdown link name
tell application id "DNtp"
try
set theRecords to selected records
if theRecords = {} then error "Nothing selected"
set theEscapePattern to "\\,|\\!|\\?|\\.|\\(|\\)|\\[|\\]|\\{|\\}|\\*|\\\\|\\^|\\+|\\<|\\>|\\||\\$|\\="
repeat with thisRecord in theRecords
set theType to (type of thisRecord) as string
if theType is in {"markdown", "«constant ****mkdn»"} then
set the_record to {}
set theWikiLinkRecords to outgoing Wiki references of thisRecord
if theWikiLinkRecords ≠ {} then
repeat with thisWikiRecord in theWikiLinkRecords
set thisWikiRecord_RefURL to reference URL of thisWikiRecord
set thisWikiRecord_Type to (type of thisWikiRecord) as string
set thisWikiRecord_Kind to kind of thisWikiRecord
set {thisWikiRecord_NameWithoutSuffix, thisWikiRecord_Suffix} to {item 1, item 2} of my recordName(name of thisWikiRecord, filename of thisWikiRecord)
set end of the_record to {namewithoutsuffix_:thisWikiRecord_NameWithoutSuffix, suffix_:thisWikiRecord_Suffix, rurl_:thisWikiRecord_RefURL, neglookbehind_:{"\\t", "\\["}, neglookahead_:{("(\\." & thisWikiRecord_Suffix & ")?" & "\\]\\(") as string}, pattern_:"", type_:thisWikiRecord_Type, kind_:thisWikiRecord_Kind}
end repeat
set theLinkTexts to {}
set theSource to source of thisRecord
set theSource_Body to item 2 of my tid(theSource, ("</head>" & linefeed & "<body>") as string)
set theURLs to get links of theSource_Body
if theURLs ≠ {} then
repeat with thisURL in theURLs
set thisURL to thisURL as string
set thisURL_escaped to my regexReplace(thisURL, theEscapePattern, "\\\\$0")
set thisURL_LinkTexts to my regexFind(theSource_Body, (("(?<=\\<a href=\"" & thisURL_escaped & "\">)(.*?)(?=\\</a\\>)") as string))
repeat with thisLinkText in thisURL_LinkTexts
set thisLinkText to thisLinkText as string
if thisLinkText starts with "[[" and thisLinkText ends with "]]" then set thisLinkText to (characters 3 thru -3 in thisLinkText) as string
if theLinkTexts does not contain thisLinkText then set end of theLinkTexts to thisLinkText
set thisLinkText_decoded to my decodeHTML(thisLinkText)
if thisLinkText_decoded ≠ thisLinkText then set end of theLinkTexts to thisLinkText_decoded
end repeat
end repeat
end if
repeat with this_record in the_record
set thisWikiRecord_NameWithoutSuffix to namewithoutsuffix_ of this_record
set thisWikiRecord_NameWithoutSuffix_Length to length of thisWikiRecord_NameWithoutSuffix
set thisSuffix to ("." & (suffix_ of this_record)) as string
considering case
repeat with thisLinkText in theLinkTexts
set thisLinkText to thisLinkText as string
if thisWikiRecord_NameWithoutSuffix is in thisLinkText then
if thisWikiRecord_NameWithoutSuffix ≠ thisLinkText then
set thisSubStringOffsets to my getSubStringOffsets(thisWikiRecord_NameWithoutSuffix, thisLinkText)
set thisLinkText_Length to length of thisLinkText
repeat with thisOffset in thisSubStringOffsets
if thisOffset > 1 then
set thisNegLookbehind to characters 1 thru (thisOffset - 1) in thisLinkText as string
set thisNegLookbehind_escaped to ("(\\[)?" & my regexReplace(thisNegLookbehind, theEscapePattern, "\\\\$0")) as string
if neglookbehind_ of this_record does not contain thisNegLookbehind_escaped then
set end of neglookbehind_ of this_record to thisNegLookbehind_escaped
end if
end if
if ((thisOffset + thisWikiRecord_NameWithoutSuffix_Length)) < thisLinkText_Length then
set thisNegLookahead to characters (thisOffset + thisWikiRecord_NameWithoutSuffix_Length) thru -1 in thisLinkText as string
if thisNegLookahead ≠ thisSuffix then
set thisNegLookahead_escaped to (my regexReplace(thisNegLookahead, theEscapePattern, "\\\\$0") & "(\\]\\()?") as string
if neglookahead_ of this_record does not contain thisNegLookahead_escaped then
set end of neglookahead_ of this_record to thisNegLookahead_escaped
end if
end if
end if
end repeat
end if
end if
end repeat
end considering
end repeat
set newText to plain text of thisRecord
repeat with this_record in the_record
set thisWikiRecord_NameWithoutSuffix to namewithoutsuffix_ of this_record
set thisWikiRecord_NameWithoutSuffix_escaped to my regexReplace(thisWikiRecord_NameWithoutSuffix, theEscapePattern, "\\\\$0")
set thisWikiRecord_RefURL to rurl_ of this_record
set thisWikiRecord_Suffix to suffix_ of this_record
if useSuffix = true then
set thisWikiRecord_Type to type_ of this_record
set thisWikiRecord_Kind to kind_ of this_record
if thisWikiRecord_Type is in {"group", "«constant ****DTgr»", "smart group", "«constant ****DTsg»"} or thisWikiRecord_Kind = "Tag" then
set thisMarkdownLink to ("[" & thisWikiRecord_NameWithoutSuffix_escaped & "](" & thisWikiRecord_RefURL & ")") as string
else
set thisMarkdownLink to ("[" & thisWikiRecord_NameWithoutSuffix_escaped & "." & thisWikiRecord_Suffix & "](" & thisWikiRecord_RefURL & ")") as string
end if
else
set thisMarkdownLink to ("[" & thisWikiRecord_NameWithoutSuffix_escaped & "](" & thisWikiRecord_RefURL & ")") as string
end if
set thisPattern to ("(?<!" & my tid((neglookbehind_ of this_record), "|") & ")" & "(\\[\\[)?" & thisWikiRecord_NameWithoutSuffix_escaped) as string
set thisPattern to (thisPattern & "(?!" & my tid((neglookahead_ of this_record), "|") & ")") as string
set thisPattern to (thisPattern & "(\\." & thisWikiRecord_Suffix & ")?" & "(\\]\\])?" & "(\\." & thisWikiRecord_Suffix & ")?") as string
set pattern_ of this_record to thisPattern
set newText to my regexReplace(newText, thisPattern, thisMarkdownLink)
end repeat
set plain text of thisRecord to newText
end if
end if
end repeat
on error error_message number error_number
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, theSuffix}
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 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 regexFind(theText, thePattern)
try
set aString to current application's NSString's stringWithString:theText
set {theExpr, theError} to current application's NSRegularExpression's regularExpressionWithPattern:(thePattern) options:0 |error|:(reference)
set theMatches to theExpr's matchesInString:aString options:0 range:{0, aString's |length|()}
set theResults to {}
repeat with aMatch in theMatches
set theRange to (aMatch's rangeAtIndex:0)
set theString to (aString's substringWithRange:theRange) as text
if theString is not in theResults then
set end of theResults to theString
end if
end repeat
return theResults
on error error_message number error_number
activate
display alert "Error: Handler \"regexFind\"" message error_message as warning
error number -128
end try
end regexFind
on regexReplace(theText, thePattern, theRepacement)
try
set theString to current application's NSString's stringWithString:theText
set newString to theString's stringByReplacingOccurrencesOfString:(thePattern) withString:(theRepacement) options:(current application's NSRegularExpressionSearch) range:{location:0, |length|:length of theText}
set newText to newString as string
on error error_message number error_number
activate
display alert "Error: Handler \"regexReplace\"" message error_message as warning
error number -128
end try
end regexReplace
on decodeHTML(theText)
try
-- https://macscripter.net/viewtopic.php?pid=190404#p190404
set ca to current application
set str to ca's class "NSMutableString"'s stringWithString:(theText)
set HTMLData to str's dataUsingEncoding:(ca's NSUTF8StringEncoding)
set attributedStr to ca's class "NSAttributedString"'s alloc()'s initWithHTML:(HTMLData) documentAttributes:(missing value)
set decodedString to attributedStr's |string|()
return decodedString as text
on error error_message number error_number
activate
display alert "Error: Handler \"decodeHTML\"" message error_message as warning
error number -128
end try
end decodeHTML
on getSubStringOffsets(theSubstring, theText)
try
set theSubstringOffsets to {}
set x to 1
repeat (count (characters in theText)) times
set thisOffset to (offset of theSubstring in (characters x thru -1 in theText) as string)
if thisOffset > 0 then
set end of theSubstringOffsets to (thisOffset + x - 1)
set x to x + thisOffset
else
exit repeat
end if
end repeat
return theSubstringOffsets
on error error_message number error_number
activate
display alert "Error: Handler \"getSubStringOffsets\"" message error_message as warning
error number -128
end try
end getSubStringOffsets