How to support this blog?
Search the site:
Finder selected files, or a scratchpad, in Emacs
# about 3 years ago: Open a file in your editor of choice.
# This script is a way to either
# • open in Emacs the files selected in Finder
# or
# • open a scratchpad in Emacs when you need to jot down information.
# The script can be adapted to work with any text editor.
# It tests whether Finder was front when the script was launched *and*
# whether it had selected files.
# If either is negative, it opens a scratchpad with a name that's set here.
# Otherwise is opens the files selected in Finder.
# Personal settings:
# Obviously, your Emacs.app file is located in a different place:
set myEmacsAppPath to "/Users/******/Documents/Repositories/emacs/nextstep/"
# This is the name of the empty default Emacs buffer you want to open:
set myScratchBufferName to "turlututu"
# This part is unlikely to change, it assumes that you use the emacsclient
# that corresponds to the selected Emacs.app. And that you run Emacs as a server.
set myEmacsclient to myEmacsAppPath & "Emacs.app/Contents/MacOS/bin/emacsclient"
set myEmacsApp to myEmacsAppPath & "Emacs.app"
# saved by: https://forum.latenightsw.com/t/how-an-applescript-applet-can-get-the-frontmost-application-other-than-itself/2482/7
# This makes sure that this script is not mistaken for the frontmost application.
# The delay works at 0.2 on my machine, 0.1 is not enough.
tell application "System Events"
tell (first application process whose frontmost is true)
set frontmost to false
set visible of it to false
delay 0.2
end tell
set previously_active_app to item 1 of (get name of processes whose frontmost is true and visible is true)
end tell
# Now that we know whether Finder was previously front or not, we can put Emacs to the front.
try
tell application "System Events" to tell process "Emacs" to set frontmost to true
on error
tell application myEmacsApp
activate
delay 1
end tell
end try
# The script's main logic is here.
if previously_active_app is "Finder" then
# If Finder is the active application when the script is launched, either there is
# or there is no selection.
try
# This is the weird part. There are cases when there is no selection but the assignment
# is not considered an error, hence I test whether item 1 of the selection exists.
tell application "Finder" to set fileSelection to its selection
item 1 of fileSelection exists
on error
# If item 1 of selection does not exist, there is no selection and the error branches out here.
# A scratchpad is opened in Emacs.
set myCommand to myEmacsclient & " -n -e \"(switch-to-buffer \\\"" & myScratchBufferName & "\\\")\""
do shell script myCommand
return
end try
# Now that we have checked for that non-selection error, we can work on the selection.
repeat with selectedFile in fileSelection
set selectedFile to (POSIX path of (selectedFile as alias))
set myCommand to myEmacsclient & " -n -e \"(find-file " & "\\\"" & selectedFile & "\\\"" & ")\""
do shell script myCommand
end repeat
return
else
# And if Finder was not frontmost when the script was launched, then we just intended to
# open a scratchpad in Emacs.
set myCommand to myEmacsclient & " -n -e \"(switch-to-buffer \\\"" & myScratchBufferName & "\\\")\""
do shell script myCommand
return
end if
# Et voilà.
# Now, save the script in the format that corresponds to the way you usually launch scripts.
# I prefer the "myAppScript.app" way so that I can launch my script by calling it from Spotlight.
# I call this one ">Emacs.app".
emacs regex with emacs lisp
June 28 update: using \#1 instead of (string-to-number \1)
A reader on reddit mentionned that the manual also had the "\#d" construct to replace the often used (string-to-number \d) function.
That regex-replace improvement was mentionned in Stevve Yegge's emacs 22 introduction, back in 2006.
Last but not least, I noticed that the whole post was originally written with (string-as-number ...) when the correct function name is (string-to-number ...)
Not strictly related to translation but here is what's happening...
I've resumed studies last year, trying to finish an MA in Japan Studies I started 25 years ago.
For the first year, I only have to write a 30ish pages dissertation on my subject (representation of women in kendo magazines in Japan) and I decided to go the emacs + org-mode way, with the easy export to ODF function that's packaged with the thing.
So I decided to write each chapter in a different org file, and send them one by one to my director. But then, for the final delivery I needed to put all that in one big file and was faced with the fact that all my footnotes would need to be re-indexed manually because each file had notes starting at 1...
I usually use BBedit for any serious regex work. Mostly because the interface is clearer than emacs, and the regexp feels more modern (\d vs [:digit:])
But one thing you can't do in BBEdit is to send commands to the replace string. For ex, in my case, add 21 to the matching number, which seems pretty trivial, when you think of it, but doing that will involve other technologies, like using perl or some other command line thing.
In emacs, however, everything can be interpreted as an expression, hence you can insert code wherever you want and get the result from that code right in the document.
The org-mode footnotes all look like [fn:12], where "12" is the note number that I need to replace with an incremented number. Since there are no instances of fn:\d+ without the brackets that are not footnotes, I figured I could just be searching for that string:
fn:\([:digit:]+\)
Notice that in emacs, "(" and ")" need to be escaped, also I could have used the [0-9] class.
In BBedit I'd just need:
fn:(\d+)
And now I need to replace that with the expression that will add 21 to the number.
In BBEdit, I'd be stuck here. I just can't add anything to a match. In emacs, I can replace the match with that:
fn:\,(+ 21 (string-to-number \1))
The emacs lisp expression is "(+ 21 (string-to-number \1))", which means "convert the \1 match that is a string into its numerical value and add 21 to it".
But, wasn't \1 supposed to match [0-9]+, which is a number? Well, yes, but really it's just digits, hence strings, that have no numerical value whatsoever, so first, we need the expression to convert them to a numerical value before adding 21 to them.
Now, the trick is to have the expression be handled as an operation and not as an arbitrary string, and that's where the "\," prefix comes into play.
"\," tells the replace engine that the string that follows must be interpreted as an emacs lisp expression and not as a mere string. With it, the regexp replaces properly adds 21 to my note numbers, and I get two dozen footnotes updated in one fell swoop...
I love BBEdit and its people, but emacs is really a gift that keeps on giving.
Here are some handy references:
- the emacs
regexp-replacefunction - Regexp Replacement
- the emacs regexp syntax
- Syntax of Regular Expressions
- the emacs-lisp
string-to-numberfunction - Conversion of Characters and Strings
And here is a really super short introduction to lisp syntax
There is no real need to have a very deep understanding of emacs lisp to use this regexp-replace function. Just remember that a lisp expression generally looks like this:
(operator operands)
Where the operator is a generally a function, like + or string-to-number above, and the operands can be any expression that is accepted by the operator. So, here:
(+ 21 (string-to-number \1))
means:
add 21 to the result of the expression (string-to-number \1)
with (string-to-number \1) meaning:
convert the string matched by \1 to its numeric value
Obviously, if \1 is not a string, the conversion will fail and the addition won't work. And without that conversion, if we had just added \1 as a string, the addition that expects numbers as operands would have failed.
I just realized that this is my first emacs lisp related post ever ! I'd like to thank that person I met in Tokyo about 15 years ago who showed me the way. It's an egg that definitely took some time to hatch...
Popular, if not outdated, posts...
-
6/12/2024 update My version of macOS is too old to be able to use brew reliably since the package manager deprecated support for Monterey (m...
-
How do you automate the scheduling of a script/application launching (or any kind of file opening)? macOS provides at least two solutions w...
-
Fast forward to 2023... Most of what I wrote below is correct. But unless you have lots of time on your hands (or work on very difficult rec...
-
<? xml version = '1.0' encoding = "UTF-8" ?> <!-- Ce document est une tentative pour créer une transformation ...
-
# This script a huge improvement on my original script that appeared here # about 3 years ago: Open a file in your editor of choice . # T...