Link to New… Ulysses

I like to keep my note files in Ulysses instead of individual files, so I hacked together this script to let me and anyone else do that. It’s really not pretty, but since the Ulysses x-callback-url for creating new documents doesn’t provide a link to the new sheet I couldn’t think of another way. It’s heavily reliant on delays so some may need increasing for your system.

New Document

set linkedTitle to "$title"
set linkedURL to "$link"

tell application "UlyssesMac" to activate
delay 0.3

tell application "System Events"
	tell process "Ulysses"
		-- 1. create a new document
		if enabled of menu item "Library…" of menu 1 of menu item "Open from…" of menu 1 of menu bar item "File" of menu bar 1 then
			click menu item "Library…" of menu 1 of menu item "Open from…" of menu 1 of menu bar item "File" of menu bar 1
			delay 0.1
			keystroke "Inbox"
			delay 0.3
			keystroke return
			if enabled of menu item "New Sheet" of menu 1 of menu bar item "File" of menu bar 1 then
				click menu item "New Sheet" of menu 1 of menu bar item "File" of menu bar 1
				delay 0.3
				-- 2. name it after the current context
				tell application "System Events"
					keystroke "[" & linkedTitle & "]"
				end tell
				keystroke linkedURL
				keystroke return
			end if
		end if
	end tell
end tell
-- 3. open it — Allready open
-- 4. return the URL of the new item — Copy script from Get Address
use framework "AppKit"
use scripting additions

-- get Ulysses authorization token
try
	set authId to (do shell script "defaults read com.cogsciapps.hook  auth_id")
on error errMsg
	open location "ulysses://x-callback-url/authorize?appname=hook&x-success=hook://authorization-callback/access-token///"
	return
end try

-- wait until shift key isn't held down
property NSEvent : a reference to current application's NSEvent
property NSShiftKeyMask : a reference to 131072
set shift_down to true
repeat while shift_down
	set modifier_flags to NSEvent's modifierFlags()
	set shift_down to ((modifier_flags div (get NSShiftKeyMask)) mod 2) = 1
end repeat

-- Select Sheets or Library
tell application "System Events"
	tell process "Ulysses"
		if enabled of menu item "Clear Markup" of menu 1 of menu bar item "Markup" of menu bar 1 then
			-- Editor selected
			-- Select Sheets view
			-- 123 = left arrow key
			key code 123 using {option down, command down}
		else
			-- Editor not selected
			if not enabled of menu item "Reveal in Group" of menu 1 of menu bar item "File" of menu bar 1 then
				-- Attachments selected
				-- Select Sheets view
				key code 123 using {option down, command down}
				delay 0.2
				key code 123 using {option down, command down}
			end if
			-- Attachments not selected
			-- else Sheets or Library selected already
		end if
	end tell
end tell

-- get item ID
tell application id "com.ulyssesapp.mac"
	activate
	tell application "System Events"
		keystroke "c" using {option down, control down, command down}
	end tell
end tell
delay 0.1
set s to (the clipboard)
set AppleScript's text item delimiters to "id="
set itemId to text item 2 of s

-- use x-callback to get title
tell application id "com.ulyssesapp.mac"
	set myUrl to "ulysses://x-callback-url/get-item?id=" & itemId & "&recursive=NO&access-token=" & authId & "&x-success=hook://title-callback/targetName///?"
	open location myUrl
end tell
get "ulysses://" & itemId

@LucB

  1. The $link Hook’s providing me that I put in the note text doesn’t work — it provides what looks like a properly formatted Hook URL but it doesn’t seem to work or be the same as when I Copy as Link manually from the original context. Am I using $link incorrectly here?
  2. I’ve had to duplicate the Get Address script in this script. Is there a way I can just call that script from within New Document?

I can’t believe you made that work, stevelw, you’re a hero for trying figuring this out and hacking it together

  1. $link should be replaced with the URL with “$$$” and the title of the document encrypted in base 64 appended to it
    e.g. “hook://ulysses/nZ1PkBDwaIySNPSh0zN_TA$$$VGVjaG5vcGhvYmlh”
    “hook://ulysses/nZ1PkBDwaIySNPSh0zN_TA” is the link
    “$$$” is just a separator to make it easy to parse
    “VGVjaG5vcGhvYmlh” is the title of the linked doc, encoded in base64
    In my experience though, Ulysses ignores the extra characters and opens these links, so something else might be going on. How do the links differ from links you get with “Copy as Link”?

  2. Unfortunately, there is no way to call one script from within another. The only way we could do that is text substituting the whole script for $get_address and that would probably serve your purposes, but it would make all kinds of new scripting bugs possible or likely, such as mismatches of scope, and duplicate variable names, and nested substitutions.

1 Like

I’ve been tinkering with Hook’s x-callback-url support. Ulysses’ x-callback-url/new-sheet does provide the sheet ID in the x-success callback and so I was able to create a ‘Link to New’ script for Ulysses which doesn’t rely on UI programming. It should be in the next build for you to check out.

Here’s a preview of what it looks like:

do shell script "open 'ulysses://x-callback-url/new-sheet?text=$encoded_title&x-success=hook://x-callback-url/link?src=$encoded_link%26scheme=ulysses%26identifierKey=targetId%26titleKey=targetName'"

Ulysses will create the new sheet and callback

hook://x-callback-url/link?src=<src_document_URL>&scheme=ulysses&identifierKey=targetId&titleKey=targetName&targetId=<id>&targetName=<title>

and Hook will link together<src_document_URL> and ulysses://<id>

1 Like

I’ve figured out what’s happening there — the ‘?’ character is encoded as %3F in $link. If I change that, then you’re right — the $$$… is handled by Hook if it’s there.

That’s fantastic — I hadn’t read that bit of the documentation as it wasn’t listed under ‘open’. Please push this out soon! :slight_smile:

I just tried it out — that’s beautiful, thank you. Very quick and reliable. Only improvement would be to position the cursor in the note after creating it.

The Open Item script runs after Link to New to open the new item, and we can invoke a “tab” keypress to move the focus from the sheets view to the editor

Try replacing Ulysses’ Open Item script with this.

set sheetID to "$0"
set sheetID to text 11 thru -1 of sheetID
set ulyssesURL to "ulysses://x-callback-url/open?id=" & sheetID
open location ulyssesURL
tell application id "com.soulmen.ulysses-setapp"
    activate
end tell

-- press tab key to position cursor in editor
tell application "System Events"
  key code 48
end tell

Note: I’m using the setapp version of Ulysses, if you use the standalone version, replace the fifth line with tell application ID "com.ulyssesapp.mac"

1 Like

Thanks, v45 is working well to place the cursor in the editor, but ideally the cursor would be at the end of the line not the beginning. It would also make sense to markup the title.

# <TITLE>

<CURSOR>

do shell script "open 'ulysses://x-callback-url/new-sheet?text=%23%20$encoded_title%0D%0D%0D&x-success=hook://x-callback-url/link?scheme=ulysses%26src=$encoded_link%26identifierKey=targetId%26titleKey=targetName'"

I have to insert three return characters to get two new lines for some reason - may be a Ulysses bug.

To move the cursor to the end I’d need to do the below:

tell application "System Events"
	key code 125 using {command down}
end tell

But I can’t put it in the New Document script (as it would be done before the new item is made, even with a delay) and I can’t put it in the Open Item script (as opening any item would move to the end instead of the beginning)

Any ideas?

Well, this is getting into kind of crazy gonzo scripting territory, but I’ve got an idea should do what you want:

-- Link to New
do shell script "open 'ulysses://x-callback-url/new-sheet?text=%23%20$encoded_title%0D%0D%0Dnew-document&x-success=hook://x-callback-url/link?scheme=ulysses%26src=$encoded_link%26identifierKey=targetId%26titleKey=targetName'"

The important change is text=%23%20$encoded_title%0D%0D%0Dnew-document which creates a new document that looks like:

$encoded_title

new-document

Where the last paragraph of the document is some identifying text, in this case “new-document”

Then, in the Open Item script, we check for that identifier text, which tells us that it’s a new document. And then move the cursor to the appropriate position. And clean up the “new-document” identifier text

-- Open Item
set myId to "$0"
set myId to text 11 thru -1 of myId
set myUrl to "ulysses://x-callback-url/open?id=" & myId
open location myUrl
tell application id "com.soulmen.ulysses-setapp"
	activate
end tell
-- move cursor to editor
-- get text content of editor
tell application "System Events"
	key code 48 -- TAB
	delay 0.2
	key code 0 using {command down} -- ⌘A
	delay 0.1
	key code 8 using {command down} -- ⌘C
	delay 0.1
end tell
-- check content for "new-document"
set content to «class utf8» of (the clipboard as record)
if last paragraph of content is equal to "new-document" then
    -- move cursor to end
    -- delete "new-document"
	tell application "System Events"
		key code 125 -- DOWN
		key code 123 using {command down, shift down} -- ⌘⇧LEFT
		key code 51 -- DELETE		
	end tell
else
   -- move cursor to beginning
	tell application "System Events"
		key code 126 -- UP			
	end tell
	
end if

This does overwrite the contents of your clipboard.
Hook will save and restore your clipboard before and after executing the Get Name and Get Address scripts. It really ought to do it before Open Item and Link to New, and I’m going to fix that now, but until that change goes into effect it’s an issue with this script.

edit: once again, make note of the bundle ID in the Open Item script and change it as needed.

1 Like