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


Popular posts (last 30 days):