dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

org-roam-protocol.el (8975B)


      1 ;;; org-roam-protocol.el --- Protocol handler for roam:// links  -*- coding: utf-8; lexical-binding: t; -*-
      2 
      3 ;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com>
      4 ;; Author: Jethro Kuan <jethrokuan95@gmail.com>
      5 ;; URL: https://github.com/org-roam/org-roam
      6 ;; Keywords: org-mode, roam, convenience
      7 ;; Version: 2.2.2
      8 ;; Package-Requires: ((emacs "26.1") (org "9.4") (org-roam "2.1"))
      9 
     10 ;; This file is NOT part of GNU Emacs.
     11 
     12 ;; This program is free software; you can redistribute it and/or modify
     13 ;; it under the terms of the GNU General Public License as published by
     14 ;; the Free Software Foundation; either version 3, or (at your option)
     15 ;; any later version.
     16 ;;
     17 ;; This program is distributed in the hope that it will be useful,
     18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20 ;; GNU General Public License for more details.
     21 ;;
     22 ;; You should have received a copy of the GNU General Public License
     23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
     24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     25 ;; Boston, MA 02110-1301, USA.
     26 
     27 ;;; Commentary:
     28 ;;
     29 ;; This extension extends `org-protocol', adding custom Org-roam handlers to it
     30 ;; to provide the next new protocols:
     31 ;;
     32 ;; 1. "roam-node": This protocol simply opens the node given by the node ID
     33 ;; 2. "roam-ref": This protocol creates or opens the node with the given REF
     34 ;;
     35 ;; You can find detailed instructions on how to setup the protocol in the
     36 ;; documentation for Org-roam.
     37 ;;
     38 ;;; Code:
     39 (require 'org-protocol)
     40 (require 'ol) ;; for org-link-decode
     41 (require 'org-roam)
     42 
     43 ;;; Options
     44 (defcustom org-roam-protocol-store-links nil
     45   "Whether to store links when capturing websites with `org-roam-protocol'."
     46   :type 'boolean
     47   :group 'org-roam)
     48 
     49 (defcustom org-roam-capture-ref-templates
     50   '(("r" "ref" plain "%?"
     51      :target (file+head "${slug}.org"
     52                         "#+title: ${title}")
     53      :unnarrowed t))
     54   "The Org-roam templates used during a capture from the roam-ref protocol.
     55 See `org-roam-capture-templates' for the template documentation."
     56   :group 'org-roam
     57   :type '(repeat
     58           (choice (list :tag "Multikey description"
     59                         (string :tag "Keys       ")
     60                         (string :tag "Description"))
     61                   (list :tag "Template entry"
     62                         (string :tag "Keys           ")
     63                         (string :tag "Description    ")
     64                         (choice :tag "Capture Type   " :value entry
     65                                 (const :tag "Org entry" entry)
     66                                 (const :tag "Plain list item" item)
     67                                 (const :tag "Checkbox item" checkitem)
     68                                 (const :tag "Plain text" plain)
     69                                 (const :tag "Table line" table-line))
     70                         (choice :tag "Template       "
     71                                 (string)
     72                                 (list :tag "File"
     73                                       (const :format "" file)
     74                                       (file :tag "Template file"))
     75                                 (list :tag "Function"
     76                                       (const :format "" function)
     77                                       (function :tag "Template function")))
     78                         (plist :inline t
     79                                ;; Give the most common options as checkboxes
     80                                :options (((const :format "%v " :target)
     81                                           (choice :tag "Node location"
     82                                                   (list :tag "File"
     83                                                         (const :format "" file)
     84                                                         (string :tag "  File"))
     85                                                   (list :tag "File & Head Content"
     86                                                         (const :format "" file+head)
     87                                                         (string :tag "  File")
     88                                                         (string :tag "  Head Content"))
     89                                                   (list :tag "File & Outline path"
     90                                                         (const :format "" file+olp)
     91                                                         (string :tag "  File")
     92                                                         (list :tag "Outline path"
     93                                                               (repeat (string :tag "Headline"))))
     94                                                   (list :tag "File & Head Content & Outline path"
     95                                                         (const :format "" file+head+olp)
     96                                                         (string :tag "  File")
     97                                                         (string :tag "  Head Content")
     98                                                         (list :tag "Outline path"
     99                                                               (repeat (string :tag "Headline"))))))
    100                                          ((const :format "%v " :prepend) (const t))
    101                                          ((const :format "%v " :immediate-finish) (const t))
    102                                          ((const :format "%v " :jump-to-captured) (const t))
    103                                          ((const :format "%v " :empty-lines) (const 1))
    104                                          ((const :format "%v " :empty-lines-before) (const 1))
    105                                          ((const :format "%v " :empty-lines-after) (const 1))
    106                                          ((const :format "%v " :clock-in) (const t))
    107                                          ((const :format "%v " :clock-keep) (const t))
    108                                          ((const :format "%v " :clock-resume) (const t))
    109                                          ((const :format "%v " :time-prompt) (const t))
    110                                          ((const :format "%v " :tree-type) (const week))
    111                                          ((const :format "%v " :unnarrowed) (const t))
    112                                          ((const :format "%v " :table-line-pos) (string))
    113                                          ((const :format "%v " :kill-buffer) (const t))))))))
    114 
    115 ;;; Handlers
    116 (defun org-roam-protocol-open-ref (info)
    117   "Process an org-protocol://roam-ref?ref= style url with INFO.
    118 
    119 It opens or creates a note with the given ref.
    120 
    121   javascript:location.href = \\='org-protocol://roam-ref?template=r&ref=\\='+ \\
    122         encodeURIComponent(location.href) + \\='&title=\\=' + \\
    123         encodeURIComponent(document.title) + \\='&body=\\=' + \\
    124         encodeURIComponent(window.getSelection())"
    125   (unless (plist-get info :ref)
    126     (user-error "No ref key provided"))
    127   (org-roam-plist-map! (lambda (k v)
    128                          (org-link-decode
    129                           (if (equal k :ref)
    130                               (org-protocol-sanitize-uri v)
    131                             v))) info)
    132   (when org-roam-protocol-store-links
    133     (push (list (plist-get info :ref)
    134                 (plist-get info :title)) org-stored-links))
    135   (org-link-store-props :type (and (string-match org-link-plain-re
    136                                                  (plist-get info :ref))
    137                                    (match-string 1 (plist-get info :ref)))
    138                         :link (plist-get info :ref)
    139                         :annotation (org-link-make-string (plist-get info :ref)
    140                                                           (or (plist-get info :title)
    141                                                               (plist-get info :ref)))
    142                         :initial (or (plist-get info :body) ""))
    143   (raise-frame)
    144   (let ((org-capture-link-is-already-stored t))
    145     (org-roam-capture-
    146      :keys (plist-get info :template)
    147      :node (org-roam-node-create :title (plist-get info :title))
    148      :info (list :ref (plist-get info :ref)
    149                  :body (plist-get info :body))
    150      :templates org-roam-capture-ref-templates))
    151   nil)
    152 
    153 (defun org-roam-protocol-open-node (info)
    154   "This handler simply opens the file with emacsclient.
    155 
    156 INFO is a plist containing additional information passed by the protocol URL.
    157 It should contain the FILE key, pointing to the path of the file to open.
    158 
    159   Example protocol string:
    160 
    161 org-protocol://roam-node?node=uuid"
    162   (when-let ((node (plist-get info :node)))
    163     (raise-frame)
    164     (org-roam-node-visit (org-roam-populate (org-roam-node-create :id node)) nil 'force))
    165   nil)
    166 
    167 (push '("org-roam-ref"  :protocol "roam-ref"   :function org-roam-protocol-open-ref)
    168       org-protocol-protocol-alist)
    169 (push '("org-roam-node"  :protocol "roam-node"   :function org-roam-protocol-open-node)
    170       org-protocol-protocol-alist)
    171 
    172 (provide 'org-roam-protocol)
    173 
    174 ;;; org-roam-protocol.el ends here