How to support this blog?

To support this blog, you can hire me as an OmegaT consultant/trainer, or you can send translation and project management jobs my way.

Search the site:

Automator: Finder → Launch Application

I don’t know why it never occurred to me, but there is an Automator action from Finder that’s called Launch Application and that you can use to:

  • register an Applescript (or any other) application in the Services menu,
  • assign a shortcut to it,
  • launch it without having to call it with Spotlight.

That saves the necessity to separately manage your AppleScript code, plus debugging from Automator is really not fun. . .




And it also gives you the ability to automatically call the application instead of using either Spotlight or the running application navigator (I don’t know what it is called, the thing that you trigger when you hit Command+Tab).


Anyway, now I have my Emacs Capture app from this weekend directly available with a shortcut, the only problem now being to make sure that the shortcut is particular enough that it does not conflict with existing application shortcuts. . .



Haha! That shortcut seems to work anywhere but in text fields, where it calls the spellchecker dialog...


Et voilà!


ps: Shortcuts has something similar, but it looks like it won’t accept applications that are not installed in /Applications, which is a pity.

An even newer version of my Capture app

This is a newer version of what I wrote on Sunday.

I figured a number of things.

  • I’m not going to call this app at random, so I could just as well action something in Emacs when I dismiss the dialog.
  • My default does not have to be selected. If it is not selected, I can use the fact that nothing is selected as the default.

So, I decided that dismissing the script would bring Emacs to the front, so that I can just write something without anything captured.

Also, I added an option to display the Capture interactive selector in Emacs, in case I want to capture something that’s not in the list (i.e., something that I would not capture that often).

I also put handlers, to kind of prettify the code.



The next step, as written in the script, is to combine that code with the “Open with Emacs” code that I have and check whether Finder is front, in which case I either open the selection or the enclosing folder.

I’ll try to not scratch that itch before I’m done with urgent work. . .


####################################


use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions

use framework "Foundation"


#########

# First, I'll be using the Foundation framework because otherwise it 

# would be non-trivial to find "the index of a given item in my list". 

# And for that I'll just need to use NSArrays. I did not figure that out 

# by myself, I found the hint on stackoverflow.

# reference: https://stackoverflow.com/a/65690139/5511978

#########


property NSArray : class "NSArray"


#########

# Then, I'm setting my paths to Emacs and emacsclient.

#########


set myEmacs to "/.../Emacs.app"

set myEmacsclient to "/.../Emacs.app/Contents/MacOS/bin/emacsclient"


#########

# Here, I create the list of template items I want to quickly access. I 

# have many more, but the others are more about long-form writing, so I 

# figured I'd be facing Emacs when I need to access them.

# This list is basically "capture", "todo", "done", "dictionary", "notes" and "drafts".

# Then I transform that into a Foundation array

#

# "capture" allows me to display the interactive template chooser.

#########


set myList to {"capture", "à faire", "fait", "dictionnaire", "notes", "brouillon"}

set myArray to NSArray's arrayWithArray:myList


#########

# Here are the template keys that I use in my Emacs interactive capture 

# template.

# Their order corresponds to the order of the above list items.

#########


set myKeys to {"c", "a", "f", "d", "n", "b"}


#########

# Now comes the interactive item selection window. That's the thing 

# that's apparently called when I call the app. All the rest takes place 

# behind the scenes.

# I can just hit Enter without selecting anything.

# I'll use that to call the default template, which is "fait".

#

# I can hit the first letter of any item for it to be selected, then I 

# hit Enter to simulate clicking on OK.

# The "capture" (c) key is special since it allows me to display the 

# Emacs interactive template selection dialog.

# I can dismiss the dialog with either hitting Escape or clicking on 

# Cancel. But since I'm not calling the dialog by mistake, I use that 

# action to just bring Emacs to the front.

#

# I'll probably use that in a future version to call Emacs on selected 

# file and folders to open them or open dired.

#

# Then I'll need to move all that into a macOS service that I call with 

# a simple shortcut so that I don't have to:

# - call Spotlight (Cmd+Space)

# - call the app (>C)

#########


try

set captureChoice to (choose from list myList with title "Emacs" with prompt "Défaut = \"fait\"" with empty selection allowed)

set captureChoice to item 1 of captureChoice

on error

if captureChoice is false then

myEmacsComesForward()

return

end if

if length of captureChoice is 0 then

set captureChoice to "fait"

end if

end try


#########

# Here comes the place where I need Foundation's arrays.

# Basically, the line says "You just selected something, find its index in the 

# list where it belongs, and get me the letter that has the same index 

# in the myKeys list."

#

# I'm adding a few parameters to see whether I'll use the contents of 

# the clipboard or not, and if I want to automatically send the template 

# key or let Emacs propose me the interactive selection dialog.

#########


set myTemplateKey to item ((myArray's indexOfObject:captureChoice) + 1) of myKeys



if myTemplateKey is in {"d", "n"} then

set useBody to true

else

set useBody to false

end if


if myTemplateKey is in {"c"} then

set interactiveCapture to true

else

set interactiveCapture to false

end if


#########

# For 2 items, "dictionnaire" and "notes", I'm thinking that I'll 

# probably have found something in a document that I'm reading, I'll need

# to copy it for use later on in the capture buffer.

# In the case of "dictionary", it's a word that I want to check, and I'll 

# use that as the title of the captured item.

# In the case of "notes", it's probably a sentence, or a paragraph that 

# I want to keep in the body of a captured item.

# I won't use the selection for the other items.

# For that, I'll put the selection (the clipboard) into the &body part of

# the org-protocol command.

#########


if useBody is true then

set myTemplateBody to "&body=" & (the clipboard)

else if useBody is false then

set myTemplateBody to ""

end if


#########

# The &body part, though, is not super clearly explained in the 

# org-mode manual:

#

# %i              The selected text

#

# Basically, the value of &body is the contents of %i in the capture template.

# I don't know why the manual mentions "the selected text" since you can put

# whatever you want in &body.

#

# In my templates, I've used it this way:

#

# ("n" "choses à noter

# notes | à lire | code | inspiration" entry (file "~/org/memo.org")

# "* [%u]  %?\n%i" :empty-lines 0 :unnarrowed nil)

#

# Here, %i, the contents of the clipboard, will be inserted in the body 

# of the capture buffer, under the headline (notice the "\n"). And the cursor

#  (%?) is waiting for me inside the headline.

#

# or:

#

# ("d" "Dictionnaire" entry (file+datetree "/Users/suzume/org/dico.org")

# "* [%<%H:%M>] %i\n%?" :empty-lines 0 :unnarrowed nil)

#

# where %i will be inside the headline and the body of the capture 

# (supposedly the term definition) will come after the line-break, where

# the cursor is waiting for my input (%?).

#########



#########

# Et voilà !

# The org-protocol command can be built, and sent to emacsclient:

#########


if interactiveCapture is true then

set myCaptureCommand to myEmacsclient & " -e \"(org-capture)\" -n"

else if interactiveCapture is false then

set myCaptureCommand to myEmacsclient & " \"org-protocol://capture?template=" & myTemplateKey & myTemplateBody & "\""

end if



#########

# Here, I make sure that Emacs is in front of me.

# If Emacs is not launched, it is now launched, which is important, 

# because my setting also starts emacs-server, without which I could not 

# use emacsclient.

#########


myEmacsComesForward()


#########

# And last but not least, the org-protocol command is sent to the 

# shell, and with Emacs at the front with the cursor waiting for me,

# I can start working right away in my capture buffer.

#########


myEmacsDoesSomething(myCaptureCommand)


#############################################


on myEmacsComesForward()

try

tell application "System Events" to tell process "Emacs" to set frontmost to true

on error

tell application myEmacs

activate

end tell

end try

end myEmacsComesForward


on myEmacsDoesSomething(myCaptureCommand)

try

do shell script myCaptureCommand

on error

log "Emacs au premier plan"

end try

end myEmacsDoesSomething


New Capture app, with org-protocol this time.

Just about 5 years ago, I wrote a Capture (really) everywhere article where I described a simple AppleScript application that could be launched from Spotlight and that would call org-capture in a running instance of Emacs.

I had a really nice time with that app, until sandboxing became stricter, and it became difficult to reliably control applications with keystrokes sent from System Events.

I eventually rewrote the application, and it basically became a simple call to emacsclient:


set myCaptureCommand to myEmacsclient & " -e \"(org-capture)\" -n"

do shell script myCaptureCommand


Here again, the app worked well, and I could enjoy spending time crafting org-capture templates, like everyone else does when not capturing things.

Then, it occurred to me that instead of

  • calling Spotlight,
  • calling >Capture.app,
  • hitting the template key in Emacs,
  • capture my things,

I could create specialized little apps that would call a given template that I often use. Like the "fait" (done) template that I use a number of times during the day to write down what I've accomplished so far.


I started investigating in that direction, trying to use various org-capture options, but I could not make it work. Then I found a number of interesting articles that helped me figure out my new solution: 

When I read that I could use the org-protocol to set the template key, I immediately thought that I could implement a little interactive template selector in AppleScript that would automatically put me in the right capture buffer.

And that's what I've been doing today, and I'll properly document that in my daily log, with that application, when I'm done with this article...


So, first, here is the app. It's just out of the oven, it works, I've not tested it extensively, so there might be glitches here and there, but it looks OK.

The main difference is that I'm using emacsclient to work with org-protocol here, instead of having it evaluate a call to (org-capture).

When I call it, it displays the following list item selector:

If I have copied something from a document on my machine, the copied contents will be used in the headline for "dictionnaire":

Here, I had copied "統一教会" from an article I was reading, to gather notes about the organisation.

And the copied contents will be used in the body of the capture buffer if I selected "notes":

Here, it is a short article about 伊藤詩織 and her recent win in court. Now I just have to put a title and eventually write more about the item.


As usual, the explanations come as comments in the AppleScript code so that you can just copy-paste the thing and test it. Although in this case, there are many things that depend on my setup that I doubt it would work out of the box.

####################################

use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions

use framework "Foundation"


#########

# First, I'll be using the Foundation framework because otherwise it 

# would be non-trivial to find "the index of a given item in my list". 

# And for that I'll just need to use NSArrays. I did not figure that out 

# by myself, I found the hint on stackoverflow.

# reference: https://stackoverflow.com/a/65690139/5511978

#########


property NSArray : class "NSArray"


#########

# Then, I'm setting my paths to Emacs and emacsclient.

# Change the values to something that works for you.

#########


set myEmacs to "/path/to/Emacs.app"

set myEmacsclient to "/path/Emacs.app/Contents/MacOS/bin/emacsclient"



#########

# Here, I create the list of template items I want to quickly access. I 

# have many more, but the others are more about long-form writing, so I 

# figured I'd be facing Emacs when I need to access them.

# This list is basically "todo", "done", "dictionary", "notes" and "drafts".

# Then I transform that into a Foundation array

#########


set myList to {"à faire", "fait", "dictionnaire", "notes", "brouillon"}

set myArray to NSArray's arrayWithArray:myList



#########

# Here are the template keys that I use in my Emacs interactive capture 

# template.

# Their order corresponds to the order of the above list items.

#########


set myKeys to {"a", "f", "d", "n", "b"}



#########

# Now comes the interactive item selection window. That's the thing 

# that's apparently called when I call the app. All the rest takes place 

# behind the scenes.

#

# That's the thing that you see above in the first screenshot.

# I can hit the first letter of any item for it to be selected, then I 

# hit Enter to simulate clicking on OK.

#########


set captureChoice to item 1 of (choose from list myList with title "Capture" default items "fait" with prompt "Choix")



#########

# Here comes the place where I need Foundation's arrays.

# Basically, the line says "You just selected something, find its index in the 

# list where it belongs, and get me the letter that has the same index 

# in the myKeys list."

#########


set myTemplateKey to item ((myArray's indexOfObject:captureChoice) + 1) of myKeys



#########

# For 2 items, "dictionnaire" and "notes", I'm thinking that I'll 

# probably have found something in a document that I'm reading, I'll need

# to copy it for use later on in the capture buffer.

# In the case of "dictionary", it's a word that I want to check, and I'll 

# use that as the title of the captured item.

# In the case of "notes", it's probably a sentence, or a paragraph that 

# I want to keep in the body of a captured item.

# 

# I won't use the selection for the other items.

# For that, I'll put the selection (the clipboard) into the &body part of

# the org-protocol command.

#########


set myTemplateBody to ""


if myTemplateKey is in {"d", "n"} then

set myTemplateBody to "&body=" & (the clipboard)

end if


#########

# The &body part, though, is not super clearly explained in the 

# org-mode manual:

#

%i              The selected text

#

# Basically, the value of &body is the contents of %i in the capture template.

# I don't know why the manual mentions "the selected text" since you can put

# whatever you want in &body.

#

# In my templates, I've used it this way:

#

# ("n" "choses à noter

#  notes | à lire | code | inspiration" entry (file "~/org/memo.org")

# "* [%u]  %?\n%i" :empty-lines 0 :unnarrowed nil)

#

# Here, %i, the contents of the clipboard, will be inserted in the body 

# of the capture buffer, under the headline (notice the "\n"). And the cursor

#  (%?) is waiting for me inside the headline.

#

# or:

#

# ("d" "Dictionnaire" entry (file+datetree "/Users/suzume/org/dico.org")

# "* [%<%H:%M>] %i\n%?" :empty-lines 0 :unnarrowed nil)

#

# where %i will be inside the headline and the body of the capture 

# (supposedly the term definition) will come after the line-break, where

# the cursor is waiting for my input (%?).

#########



#########

# Et voilà !

# The org-protocol command can be built, and sent to emacsclient:

#########


set myOrgProtocolCommand to myEmacsclient & " \"org-protocol://capture?template=" & myTemplateKey & myTemplateBody & "\""



#########

# Here, I make sure that Emacs is in front of me.

# If Emacs is not launched yet, it is now launched, which is important, 

# because my setting also starts emacs-server, without which I could not 

# use emacsclient.

#########


try

tell application "System Events" to tell process "Emacs" to set frontmost to true

on error

tell application myEmacs

activate

end tell

end try



#########

# And last but not least, the org-protocol command is sent to the 

# shell, and with Emacs at the front with the cursor waiting for me,

# I can start working right away in my capture buffer.

#########


try

do shell script myOrgProtocolCommand

on error

display alert "ooops"

end try


#############################################

Popular, if not outdated, posts...

.docx .NET .pptx .sdf .xlsx AASync accented letters Accessibility Accessibility Inspector Alan Kay alignment Apple AppleScript ApplescriptObjC AppleTrans applications Aquamacs Arabic archive Automator backup bash BBEdit Better Call Saul bug Butler C Calculator Calendar Chinese Cocoa Command line CSV CSVConverter database defaults Devon Dictionary DITA DocBook Dock Doxygen EDICT Emacs emacs lisp ergonomics Excel external disk file formats file system File2XLIFF4j Finder Fink Font français Free software FSF Fun Get A Mac git GNU GPL Guido Van Rossum Heartsome Homebrew HTML IceCat Illustrator InDesign input system ITS iWork Japanese Java Java Properties Viewer Java Web Start json keybindings keyboard Keynote killall launchd LISA lisp locale4j localisation MacPorts Mail markdown MARTIF to TBX Converter Maxprograms Mono MS Office NeoOffice Numbers OASIS Ocelot ODF Okapi OLPC OLT OmegaT OnMyCommand oo2po OOXML Open Solaris OpenDocument OpenOffice.org OpenWordFast org-mode OSX Pages PDF PDFPen PlainCalc PO Preview programming python QA Quick Look QuickSilver QuickTime Player Rainbow RAM reggy regular expressions review rsync RTFCleaner Safari Santa Claus scanner Script Debugger Script Editor scripting scripting additions sdf2txt security Services shell shortcuts Skim sleep Smultron Snow Leopard Spaces Spanish spellchecking Spotlight SRX standards StarOffice Stingray Study SubEthaEdit Swordfish System Events System Preferences TBX TBXMaker Terminal text editing TextEdit TextMate TextWrangler The Tool Kit Time Capsule Time Machine tmutil TMX TMX Editor TMXValidator transifex Translate Toolkit translation Transmug troubleshooting TS TTX TXML UI Browser UI scripting Unix VBA vi Virtaal VirtualBox VLC W3C WebKit WHATWG Windows Wine Word WordFast wordpress writing Xcode XLIFF xml XO xslt YAML ZFS Zip