index all rss twitter github linkedin email
Álvaro Ramírez

Álvaro Ramírez

06 November 2022 Hey Emacs, change the default macOS app for…

A few weeks ago, I added an "open with" command to dwim-shell-commands.el. It's pretty handy for opening files using an external app (ie. not Emacs) other than the default macOS one.

dwim-shell-commands-macos-open-with and dwim-shell-commands-open-externally are typically enough for me to handle opening files outside of Emacs. But every now and then I'd like to change the default macOS app associated with specific file types. Now this isn't particularly challenging in macOS, but it does require a little navigating to get to the right place to change this default setting.

Back in March 2020, I tweeted about duti: a command-line utility capable of setting default applications for various document types on macOS. While I liked the ability to change default apps from the command-line, the habit never quite stuck.

Fast forward to 2022. I've been revisiting lots of my command-line usages (specially those that never stuck) and making them more accessible from Emacs via dwim-shell-command. I seldom change default apps on macOS, so my brain forgets about duti itself, let alone its arguments, order, etc. But with a dwim shell command like dwim-shell-commands-macos-set-default-app, I can easily invoke the command via swiper's counsel-M-x fuzzy terms: "dwim set".

set-default_x1.3.webp

As an added bonus, I get to reuse dwim-shell-commands--macos-apps from "open with" to quickly pick the new default app, making the whole experience pretty snappy.

(defun dwim-shell-commands-macos-set-default-app ()
  "Set default app for file(s)."
  (interactive)
  (let* ((apps (dwim-shell-commands-macos-apps))
         (selection (progn
                      (cl-assert apps nil "No apps found")
                      (completing-read "Set default app: " apps nil t))))
    (dwim-shell-command-on-marked-files
     "Set default app"
     (format "duti -s \"%s\" '<<e>>' all"
             (string-trim
              (shell-command-to-string (format "defaults read '%s/Contents/Info.plist' CFBundleIdentifier"
                                               (map-elt apps selection)))))
     :silent-success t
     :no-progress t
     :utils "duti")))

(defun dwim-shell-commands--macos-apps ()
  "Return alist of macOS apps (\"Emacs\" . \"/Applications/Emacs.app\")."
  (mapcar (lambda (path)
            (cons (file-name-base path) path))
          (seq-sort
           #'string-lessp
           (seq-mapcat (lambda (paths)
                         (directory-files-recursively
                          paths "\\.app$" t (lambda (path)
                                             (not (string-suffix-p ".app" path)))))
                       '("/Applications" "~/Applications" "/System/Applications")))))

As usual, I've added dwim-shell-commands-macos-set-default-app to dwim-shell-commands.el, which you can install via MELPA.

Did you find this tiny integration useful? Check out Hey Emacs, where did I take that photo?