Ah, I think I am conflating two separate entities. If the selected text contains and embedded link, that is what appelscript is returning.
Is there a way for me to access the “selection link” URL that is now available in 3.9?
Rick
Ah, I think I am conflating two separate entities. If the selected text contains and embedded link, that is what appelscript is returning.
Is there a way for me to access the “selection link” URL that is now available in 3.9?
Rick
What would that URL be for a selected text? BTW: as it’s apparently part of text suite, I doubt that there’s anything new about it.
That’s right, these features exist for quite a while (as far as I remember since DEVONthink Pro 1.x, probably 1.0)
For an AppleScript example:
on run
set mdLinks to mdFromLabelledLinks(selectedTextLabelLinkPairs())
set the clipboard to mdLinks
return mdLinks
end run
on selectedTextLabelLinkPairs()
tell application "DEVONthink 3"
set thinkWindow to its front think window
if exists thinkWindow then
tell thinkWindow to ¬
set refText to a reference to (its selected text)
if exists refText then
set runs to a reference to (attribute runs of refText)
my zip(text of runs, URL of runs)
else
{}
end if
else
{}
end if
end tell
end selectedTextLabelLinkPairs
on mdFromLabelledLinks(kvs)
script f
on |λ|(kv)
set {k, v} to kv
if missing value is not v then
{"[" & k & "](" & v & ")"}
else
{}
end if
end |λ|
end script
my unlines(my concatMap(f, kvs))
end mdFromLabelledLinks
on concatMap(f, xs)
set lng to length of xs
set acc to {}
tell f
repeat with i from 1 to lng
set acc to acc & (|λ|(item i of xs, i, xs))
end repeat
end tell
acc
end concatMap
on min(x, y)
if y < x then
y
else
x
end if
end min
on unlines(xs)
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
on zip(xs, ys)
set n to min(length of xs, length of ys)
set vs to {}
repeat with i from 1 to n
set end of vs to {item i of xs, item i of ys}
end repeat
return vs
end zip
Functional programming in AppleScript – impressive!
It can, of course, be expressed more parsimoniously, but perhaps not without straining a reader’s patience with the overloading of it
and its
.
Extracting just the main function:
on selectedTextLabelLinkPairs()
tell application "DEVONthink 3"
tell front think window
if exists then
tell (a reference to (its selected text))
if exists then
tell attribute runs
my zip(text of it, URL of it)
end tell
else
{}
end if
end tell
else
{}
end if
end tell
end tell
end selectedTextLabelLinkPairs
I realized my error after dissecting winter’s solution.
When I saw the feature in 3.9 allowing a direct link to a selection in pdfs, I dove into my automation scripts to make things in my workflow better. Because I know you all love automation as much as I do, I assumed that there would be a new AppleScript link to that feature so when I saw “selected text” as an option in the AS dictionary my self-delusion was complete.
Thank you for a great product and for loving making it better and AppleScript-able for those of us geeks who love to use it!
Rick
Wow. Thanks for this impressive script. I will dive into it when I can!
Rick
Currently there is no AppleScript property for a record’s selection link
, page link
, paragraph link
, or annotation link
. There is only the reference url
and item link parameters that potentially can be strung together to create such entities.
Thanks, Jim. I will look at creating this myself.
The page reference looks pretty easy to find, and the length parameter is obviously easy. Finding the start parameter though doesn’t seem straight forward other than "find"ing the selection within the total text and then hoping it’s the only text like that in the document…
I’ll keep looking and think on it some more.
Thanks!
Rick
this code creates a link into devonthink equivalent to a “selection link”. Let me know any improvements you see that need to be done.
-- Return md link to selected text
tell application id "DNtp"
set fWindow to its front window
if exists fWindow then
set refText to a reference to selected text of fWindow
if exists refText then
set attr to a reference to (attribute runs of refText)
set theText to text of attr
set theText to first item of theText
set theURL to URL of attr
set theURL to first item of theURL
-- build link
set theRecord to content record of fWindow
set allText to plain text of theRecord
set theStart to offset of theText in allText
set theStart to theStart - 1
set theLength to count of theText
set theLink to reference URL of theRecord & ¬
"?page=" & current page of fWindow & ¬
"&start=" & (theStart as string) & ¬
"&length=" & (length of theText) as string
if missing value is not theURL then
set theText to "[" & theText & "](" & theURL & ")"
end if
set returnText to ((theText & "[^" & theStart as string) & "]}" & return & return & ¬
"[^" & theStart as string) & "]: " & theLink
return returnText
end if
end if
return ""
end tell
Rick
This parameter is actually relative to beginning of the page. However, it’s possible to create selection links without having to use start
/length
parameters.
The page
and search
parameters are sufficient if the search
parameter contains the escaped content of the selected text.
Thanks, Chris
So to “fix” theLink portion in my code above, I have come up with:
set theLink to reference URL of theRecord & ¬
"?page=" & current page of fWindow & ¬
"&search=" & my urlencode(theText)
and pulled some code from stack overflow to url encode some text as follows:
on urlencode(theText)
set theTextEnc to ""
repeat with eachChar in characters of theText
set useChar to eachChar
set eachCharNum to ASCII number of eachChar
if eachCharNum = 32 then
set useChar to "%20"
else if (eachCharNum ≠ 42) and (eachCharNum ≠ 95) and (eachCharNum < 45 or eachCharNum > 46) and (eachCharNum < 48 or eachCharNum > 57) and (eachCharNum < 65 or eachCharNum > 90) and (eachCharNum < 97 or eachCharNum > 122) then
set firstDig to round (eachCharNum / 16) rounding down
set secondDig to eachCharNum mod 16
if firstDig > 9 then
set aNum to firstDig + 55
set firstDig to ASCII character aNum
end if
if secondDig > 9 then
set aNum to secondDig + 55
set secondDig to ASCII character aNum
end if
set numHex to ("%" & (firstDig as string) & (secondDig as string)) as string
set useChar to numHex
end if
set theTextEnc to theTextEnc & useChar as string
end repeat
return theTextEnc
end urlencode
Rick
Hey, Rick… let me save you a little suffering and learn you something
You can run ad-hoc JavaScript in an AppleScript via the do Javascript
command. The only requirement is it has to run in a think window
. However, you don’t have to specify a window nor does the window need to be even remotely related to the command. It’s literally do javascript "<insert script here>" in think window 1
set theText to "Hey, Rick! Here's an easier way to URL encode some text via AppleScript…"
tell application id "DNtp"
do JavaScript "encodeURIComponent(\"" & theText & "\");" in think window 1 -- The argument needs to be in escaped double quotes
end tell
---> Hey%2C%20Rick!%20Here's%20an%20easier%20way%20to%20URL%20encode%20some%20text%20via%20AppleScript%E2%80%A6
And yes @chrillek, I sometimes use this to inject a little JS into AS as the situation needs it.
This parameter should actually be optional, fixed for the next release.
Cool trick, indeed. Though I’m not sure if calling encodeURIComponent
from AS shouldn’t be considered cheating
I give JS its credit. I prefer my beloved AS, but there are definitely some great JS functions that can be employed as needed.
You guys are the best. Appreciate you!
Making this open where it can be used at any time will make this a killer feature across all scripting. Seriously.
@chrillek and I were looking at an issue recently and he had a perfect JavaScript solution. The problem was I already had a giant applescript so rewriting in JXA wouldn’t have worked for me.
But doing this would have! Nice!
It is cheating! It’s awesomely the right kind of cheating!!