(feature): emacs-lisp handling for roam:// links (#188)

We emulate org-protocol, and advise server-find-files, stripping the
roam protocol from the filename. This reduces the setup required to
open `roam://` links.
This commit is contained in:
Jethro Kuan
2020-02-26 15:35:20 +08:00
committed by GitHub
parent b382b1f21a
commit 5e76c67cf6
3 changed files with 115 additions and 30 deletions

View File

@ -4,6 +4,7 @@
### New Features
* [#182][gh-182] Support file name aliases via `#+ROAM_ALIAS`.
* [#188][gh-188] Add `org-roam-protocol`, shifting `roam://` link handling into Emacs-lisp.
### Features
* [#165][gh-165] Add templating functionality via `org-roam-templates`.
@ -97,6 +98,7 @@ Mostly a documentation/cleanup release.
[gh-143]: https://github.com/jethrokuan/org-roam/pull/143
[gh-165]: https://github.com/jethrokuan/org-roam/pull/165
[gh-182]: https://github.com/jethrokuan/org-roam/pull/182
[gh-188]: https://github.com/jethrokuan/org-roam/pull/188
# Local Variables:
# eval: (auto-fill-mode -1)

View File

@ -1,9 +1,15 @@
The setup is similar to that of org-protocol. Here `roam://` links are
The setup is the same as org-protocol. Here `roam://` links are
defined, and need to be associated with an application.
The gist of the setup is setting up a Bash script to trim off the
`roam://` prefix from the link, causing the desktop application to
call `emacsclient path/to/org-roam-file.org`.
Across all platforms, to enable `org-roam-protocol`, you have to add
the following to your init file:
```emacs-lisp
(require 'org-roam-protocol)
```
We also need to create a desktop application for emacsclient. The
instructions for various platforms are shown below:
## Linux
@ -13,25 +19,14 @@ Create a desktop application. I place mine in
```
[Desktop Entry]
Name=Org-Roam Client
Exec=/home/jethro/.local/bin/launch_emacs %u
Exec=emacsclient %u
Icon=emacs-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/roam
```
Note the `Exec` key is set to a bash script poorly named
`launch_emacs`. You can set it to whatever you want.
Create the corresponding bash script, and make it executable. Here's
how it looks like:
```bash
#!/usr/bin/env bash
emacsclient "${1#*:}"
```
Finally, associate `roam://` links with the desktop application by
Associate `roam://` links with the desktop application by
running in your shell:
```bash
@ -55,10 +50,11 @@ sudo chmod 644 /etc/opt/chrome/policies/managed/external_protocol_dialog.json
and then restart Chrome (for example, by navigating to <chrome://restart>) to
make the new policy take effect.
See [here](https://www.chromium.org/administrators/linux-quick-start) for more
info on the `/etc/opt/chrome/policies/managed` directory and
See [here](https://www.chromium.org/administrators/linux-quick-start)
for more info on the `/etc/opt/chrome/policies/managed` directory and
[here](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExternalProtocolDialogShowAlwaysOpenCheckbox)
for information on the `ExternalProtocolDialogShowAlwaysOpenCheckbox` policy.
for information on the `ExternalProtocolDialogShowAlwaysOpenCheckbox`
policy.
## Mac OS
@ -68,24 +64,17 @@ One solution to this, recommended in [Issue
[Platypus](https://github.com/sveinbjornt/Platypus). Here are the
instructions for setting up with Platypus and Chrome:
1. Create an executable `launch-emacs.sh` script:
```sh
#!/usr/bin/env bash
/usr/local/bin/emacsclient --no-wait "${1#*:}"
```
2. Install and launch Platypus (with [Homebrew](https://brew.sh/)):
1. Install and launch Platypus (with [Homebrew](https://brew.sh/)):
```sh
brew cask install playtpus
```
3. Playtpus settings:
2. Platypus settings:
- App Name: `OrgRoam`
- Script Type: `env` and `/usr/bin/env`
- Script Path: `/path/to/your/launch-emacs.sh`
- Script Path: `/path/to/emacsclient $1`
- Tick Accept dropped items and click Settings
- Tick Accept dropped files
- Tick Register as URI scheme handler

94
org-roam-protocol.el Normal file
View File

@ -0,0 +1,94 @@
;;; org-roam-protocol.el --- Protocol handler for roam:// links
;; Copyright © 2020 Jethro Kuan <jethrokuan95@gmail.com>
;; Author: Jethro Kuan <jethrokuan95@gmail.com>
;; URL: https://github.com/jethrokuan/org-roam
;; Keywords: org-mode, roam, convenience
;; Version: 0.1.2
;; Package-Requires: ((emacs "26.1") (org "9.0"))
;; This file is NOT part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; Intercept calls from emacsclient for `roam://' links.
;;
;; This is done by advising `server-visit-files' to scan the list of filenames
;; for `org-roam-protocol-the-protocol'.
;;
;; `roam://' links are expected to be absolute file locations, for example,
;; `roam:///home/me/file.org'. The `roam://' prefix is stripped, and emacsclient
;; opens the location as per usual.
;;
;; Any application that supports calling external programs with an URL as
;; argument may be used with this functionality.
;;
;; Usage:
;; ------
;;
;; 1.) Add this to your init file:
;; (add-to-list 'load-path "/path/to/org-roam-protocol.el"')
;; (require 'org-roam-protocol)
;;
;; 2.) Ensure emacs-server is up and running.
;; 3.) Try this from the command line:
;; $ emacsclient roam:///tmp/test.org
;;
;; If it works, you can now setup other applications for using this feature.
(require 'org)
;;; Variables:
(defconst org-roam-protocol-the-protocol "roam"
"This is the protocol to detect if org-roam-protocol.el is loaded.
You will have to define just one protocl handler OS-wide (MS-Windows)
or per application (Linux). That protocol handler should call emacsclient.")
;;; Code:
(defun org-roam-protocol-check-filename-for-protocol (fname)
"Check if `org-roam-protocol-the-protocol' is used in FNAME.
If the protocol is found, the protocol is stripped from fname,
and the value is passed to the server as filename.
If the function returns nil, the filename is removed from the
list of filenames passed from emacsclient to the server. If the
function returns a non-nil value, that value is passed to the
server as filename."
(let ((the-protocol (concat (regexp-quote org-roam-protocol-the-protocol)
":")))
(when (string-match the-protocol fname)
(cadr (split-string fname the-protocol)))))
(defadvice server-visit-files (before org-roam-protocol-detect-protocol-server activate)
"Advice `server-visit-files' to strip the `roam:/' protocol.
Default to `server-find-files' handling for file locations."
(let ((flist (ad-get-arg 0)))
(dolist (var flist)
;; `\' to '/' on windows.
(let ((fname (expand-file-name (car var)))
org-roam-location)
(setq org-roam-location (org-roam-protocol-check-filename-for-protocol
fname))
(when (stringp org-roam-location) ; location for Org-roam file
(setcar var org-roam-location))))))
(provide 'org-roam-protocol)
;;; org-roam-protocol.el ends here