From 0950ae3cc66a11d48510092b15526c5e13617277 Mon Sep 17 00:00:00 2001 From: Konrad Hinsen Date: Thu, 12 Mar 2020 12:34:27 +0100 Subject: [PATCH] (feature): add support for Helm's completion system (#284) adds org-roam-completion-system, supporting helm as the default completion option. --- CHANGELOG.md | 1 + doc/configuration.md | 13 +++++++++++ org-roam.el | 52 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36ad53b..0b96e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## New Features * [#269][gh-269] Add `org-roam-graphviz-extra-options` * [#257][gh-257] Add a company-backend `company-org-roam` +* [#284][gh-284] Configurable `org-roam-completion-system` with options `'default` and `'helm` ## 1.0.0-rc1 (06-03-2020) diff --git a/doc/configuration.md b/doc/configuration.md index 79a44b7..dfd0ee6 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -107,3 +107,16 @@ SVG, you may choose to set it to any compatible program: ``` (setq org-roam-graph-viewer "/path/to/image-viewer") ``` + +## Org-roam Completion System + +Org-roam offers completion when choosing note titles etc. +The completion system is configurable. The default setting, +``` +(setq org-roam-completion-system 'default) +``` +uses Emacs' standard `completing-read`. If you prefer [Helm](https://emacs-helm.github.io/helm/), use + +``` +(setq org-roam-completion-system 'helm) +``` diff --git a/org-roam.el b/org-roam.el index 5576e18..107f44b 100644 --- a/org-roam.el +++ b/org-roam.el @@ -101,6 +101,14 @@ Formatter may be a function that takes title as its only argument." :type 'boolean :group 'org-roam) +(defcustom org-roam-completion-system 'default + "The completion system to be used by `org-roam'." + :type '(radio + (const :tag "Default" default) + (const :tag "Helm" helm) + (function :tag "Custom function")) + :group 'org-roam) + ;;;; Dynamic variables (defvar org-roam--current-buffer nil "Currently displayed file in `org-roam' buffer.") @@ -594,6 +602,42 @@ specified via the #+ROAM_ALIAS property." (slug (-reduce-from #'replace (strip-nonspacing-marks title) pairs))) (s-downcase slug)))) +;;;; Completion +(defun org-roam---helm-candidate-transformer (candidates source) + (let ((prefixed-pattern (propertize + " " 'display + (propertize "[?]" 'face 'helm-ff-prefix)))) + (cons (concat prefixed-pattern " " helm-pattern) + candidates))) + +(defun org-roam--completing-read (prompt choices &optional require-match initial-input) + "Present a PROMPT with CHOICES and optional INITIAL-INPUT. +If REQUIRE-MATCH is `t', the user must select one of the CHOICES. +Return user choice." + (cond + ((eq org-roam-completion-system 'default) + (completing-read prompt choices nil require-match initial-input)) + ((eq org-roam-completion-system 'helm) + (unless (and (fboundp 'helm) + (fboundp 'helm-build-sync-source)) + (user-error "Please install helm from \ +https://github.com/emacs-helm/helm")) + (let* ((source (helm-build-sync-source prompt + :candidates (-map #'car choices) + :filtered-candidate-transformer + (and (not require-match) + #'org-roam---helm-candidate-transformer) + :fuzzy-match t)) + (title (helm :sources source + :buffer (concat "*org-roam " + (s-downcase (s-chop-suffix ":" (s-trim prompt))) + "*") + :prompt prompt + :input initial-input))) + (unless title + (keyboard-quit)) + (s-trim-left title))))) + ;;;; Org-roam capture (defun org-roam--file-path-from-id (id) "The file path for an Org-roam file, with identifier ID." @@ -763,7 +807,7 @@ If PREFIX, downcase the title before insertion." (buffer-substring-no-properties (car region) (cdr region)))) (completions (org-roam--get-title-path-completions)) - (title (completing-read "File: " completions nil nil region-text)) + (title (org-roam--completing-read "File: " completions nil region-text)) (region-or-title (or region-text title)) (target-file-path (cdr (assoc title completions))) (current-file-path (-> (or (buffer-base-buffer) @@ -825,7 +869,7 @@ point moves some characters forward. This is added as a hook to INITIAL-PROMPT is the initial title prompt." (interactive) (let* ((completions (org-roam--get-title-path-completions)) - (title (completing-read "File: " completions nil nil initial-prompt)) + (title (org-roam--completing-read "File: " completions nil initial-prompt)) (file-path (cdr (assoc title completions)))) (if file-path (find-file file-path) @@ -848,7 +892,7 @@ INFO is an alist containing additional information." (interactive) (let* ((completions (org-roam--get-ref-path-completions)) (ref (or (cdr (assoc 'ref info)) - (completing-read "Ref: " (org-roam--get-ref-path-completions) nil t)))) + (org-roam--completing-read "Ref: " (org-roam--get-ref-path-completions) t)))) (find-file (cdr (assoc ref completions))))) ;;;; org-roam-switch-to-buffer @@ -871,7 +915,7 @@ INFO is an alist containing additional information." roam-buffers))) (unless roam-buffers (user-error "No roam buffers")) - (when-let ((name (completing-read "Choose a buffer: " names-and-buffers))) + (when-let ((name (org-roam--completing-read "Buffer: " names-and-buffers t))) (switch-to-buffer (cdr (assoc name names-and-buffers)))))) ;;;; Daily notes