From 5e76c67cf68023311cbb81293f0056be7a989990 Mon Sep 17 00:00:00 2001 From: Jethro Kuan Date: Wed, 26 Feb 2020 15:35:20 +0800 Subject: [PATCH] (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. --- CHANGELOG.md | 2 + doc/graph_setup.md | 49 +++++++++-------------- org-roam-protocol.el | 94 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 30 deletions(-) create mode 100644 org-roam-protocol.el diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e16a6f..85d4159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/doc/graph_setup.md b/doc/graph_setup.md index acbf97b..db94a90 100644 --- a/doc/graph_setup.md +++ b/doc/graph_setup.md @@ -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 ) 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 diff --git a/org-roam-protocol.el b/org-roam-protocol.el new file mode 100644 index 0000000..8ae6c3d --- /dev/null +++ b/org-roam-protocol.el @@ -0,0 +1,94 @@ +;;; org-roam-protocol.el --- Protocol handler for roam:// links + +;; Copyright © 2020 Jethro Kuan +;; Author: Jethro Kuan +;; 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