Emacs as an Org capture server
The general idea is to run an Emacs server as a daemon which clients can quickly connect to via a bash script. The client executes org-capture and the frame closes upon finalizing or aborting the capture.
Running a server daemon
The first step is to get an Emacs daemon running as a server with your name of choice. For this example, I’m going to use “capture” as the server name.
From your terminal start the server daemon and give it a name
Running a client
You can connect to this server with a client by launching Emacs from the terminal with the following arguments:
emacsclient --create-frame \ --socket-name 'capture' \ --alternate-editor='' \ --no-wait
We’ll make a script out of this and add more args after we set up things on the Elisp side.
In your init.el file (or in a separate package if you like) define the functions that make this server’s clients run org-capture and close.
This function deletes the frame after you finalize a capture:
(defun my/delete-capture-frame (&rest _) "Delete frame with its name frame-parameter set to \"capture\"." (if (equal "capture" (frame-parameter nil 'name)) (delete-frame))) (advice-add 'org-capture-finalize :after #'my/delete-capture-frame)
This function is a modernized version of the info found here:
This function runs when creating a new client. It selects the correct frame and forces org-capture to show the template selection menu in the main window instead of splitting it. It also closes the frame if you abort the capture process.
(defun my/org-capture-frame () "Run org-capture in its own frame." (interactive) (require 'cl-lib) (select-frame-by-name "capture") (delete-other-windows) (cl-letf (((symbol-function 'switch-to-buffer-other-window) #'switch-to-buffer)) (condition-case err (org-capture) ;; "q" signals (error "Abort") in `org-capture' ;; delete the newly created frame in this scenario. (user-error (when (string= (cadr err) "Abort") (delete-frame))))))
Now you can flesh out the emacsclient command from earlier to run your dedicated org-capture server:
#!/bin/bash emacsclient --create-frame \ --socket-name 'capture' \ --alternate-editor='' \ --frame-parameters='(quote (name . "capture"))' \ --no-wait \ --eval "(my/org-capture-frame)"
You can bind this script to a global keybinding and you should be able to capture from ‘outside’ Emacs via that binding.