In this post, I want to briefly talk about how to set up liking to another note via [[Title of the target note]]
syntax.
This is related to official manual’s section on Completions.
See the outcome in this GIF animation.
It may not look much, but there are a couple of components working together.
-
When you type
[[
, the closing brackets]]
gets automatically inserted -
[[Title of a note]]
establishes a link (and backlink) as it is. It does not automatically change to the normal file link when you save the note -
You type two characters “in”; Emacs automatically suggests candidate notes’ titles, and the matching is case-insensitive
-
You select a candidate, and hit the
Tab
key; the candidates are narrowed down up to their common part “introduction_” (“_” indicates a space, discarding note entitled “Introduction”), and this partial completion is case-insensitive -
You hit the
Enter
key to select a note; the cursor automatically goes out of the]]
bracket, so that you can keep typing -
(Idea to tweak UX further) There is some development idea I have posed separately
-
[Added 30 Sept 2020] If you prefer auto-completion without “[[”, there is a way. Open the quote box just below here:
You can easily set up your Emacs configuration to do 1–3; I will show you how in a minute.
Point 4 turns out to require local change to code (add one line) in company-capf.el
. As far as I can see there is no easy way around it; let me know if you know a good way. I will sleep on it a couple of nights, and then will probably raise a PR in the Company project’s GitHub repo. I will show you the code change I have done to get it to work.
For Point 5, I raised a PR to the Org-roam project; Jethro and I had a brief exchange. It has turned out Jethro has been working on some changes in this area (completion-at-point
). What I am writing here might need some tweaking to align with the upcoming changes, but I believe you can still take away the principle from this brief post.
Configuration
See the excerpt of configuration with my comments relevant for points 1–3.
This is for vanilla Emacs.
;; Smartparens
;; To automatically close "]]" brackets and other parentheses,
;; you need a package called "smartparens" Set it up globally.
(smartparens-global-mode t)
;; Company
;; You need package called `company`.
;; I believe what these variables are meant to do is self-explanatory.
;; You type minimum 2 characters and wait for ¼ seconds for the candidates
;; to appear automatically. It uses a backend `company-capf` (part of
;; `company`; capf stands for "completion-at-point function"). I would
;; call it inline automatic completion. Org-roam has functions to work
;; with `company-capf`.
(add-hook 'after-init-hook 'global-company-mode)
(setq company-minimum-prefix-length 2)
(setq company-idle-delay 0.25)
(add-to-list 'company-backends 'company-capf)
;; This enables candidates matching to be case-insensitive
(setq completion-ignore-case t)
;; You need this for your org-roam part of configuration
;; This prevents it from automatically replacing [[Title of a note]]
;; into [[file:path/to/note][Title of a note]].
;;(setq org-roam-auto-replace-fuzzy-links nil)
;; Some keybindings for within Company mode
;; Use (with-eval-after-load) to defer the use of `company-active-map`.
;; Otherwise, Emacs will error when loading `init.el` as it does not
;; recognise any Company related variables and functions yet.
;; This delay is defined above as we load 'global-company-mode' with
;; `after-init-hook`.
(with-eval-after-load 'company
(define-key company-active-map (kbd "C-n") #'company-select-next)
(define-key company-active-map (kbd "C-p") #'company-select-previous))
For Doom, it has modules for Company (in :completion
as company
) and Smartparens (in :config
as (default +smartparens)
). Because these modules already set most of the variables above for you, I believe you just need to add these two variables.
;; This enables matching candidates case-insensitive
(setq completion-ignore-case t)
;; You need this for your org-roam part of configuration
;; This prevents it from automatically replacing [[Title of a note]]
;; into [[file:path/to/note][Title of a note]].
;;(setq org-roam-auto-replace-fuzzy-links nil)
Even the keybindings for Company mode seem to be done for you via the module.
Partial completion (company-complete-common
)
As far as I could check, you can’t do this with configuration alone. If your candidates contain different cases (via completion-ignore-case
set to t
), hitting a tab key does not do what the GIF animation shows you.
Your candidates are matched case-insensitive, but your partial completion works case-sensitive… I would like consistency in these two matching commands for my use case.
Long story short, you need to change the source of company-capf.el
to enable ignore-case
function – not part of the source. My sample implementation adds one line to add ignore-case
and uses completion-ignore-case
to keep consistency; it works as shown in the animated GIF in the beginning of this post.
This is it for this brief how-to tip.
I will probably come back to this post once Jethro’s new changes have been rolled into the master branch of Org-roam.
'til then, keep roaming