diff --git a/CHANGELOG.md b/CHANGELOG.md index c863bbc..3be45ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ - [#2082](https://github.com/org-roam/org-roam/pull/2082) buffer: don't destroy window if `org-roam-node-toggle` reuses window - [#2080](https://github.com/org-roam/org-roam/pull/2080) dailies: prevent multiple "dailies/" subdir expansions - [#2055](https://github.com/org-roam/org-roam/pull/2055) dailies: removed stray f require, which was causing require and compilation errors +- [#2117](https://github.com/org-roam/org-roam/pull/2117) capture: preserve trailing whitespace content in capture templates + ### Changed - [#2060](https://github.com/org-roam/org-roam/pull/2060) node: added double acute accent normalization for Unicode characters in titles - [#2040](https://github.com/org-roam/org-roam/pull/2040) completions: fix completions display-width for Helm users diff --git a/org-roam-capture.el b/org-roam-capture.el index a00f71b..47e9a9f 100644 --- a/org-roam-capture.el +++ b/org-roam-capture.el @@ -505,7 +505,7 @@ Return the ID of the location." (set-buffer (org-capture-target-buffer path)) (when new-file-p (org-roam-capture--put :new-file path) - (insert (org-roam-capture--fill-template head t))) + (insert (org-roam-capture--fill-template head 'ensure-newline))) (widen) (setq p (goto-char (point-min)))) (`(file+head+olp ,path ,head ,olp) @@ -515,7 +515,7 @@ Return the ID of the location." (widen) (when new-file-p (org-roam-capture--put :new-file path) - (insert (org-roam-capture--fill-template head t))) + (insert (org-roam-capture--fill-template head 'ensure-newline))) (setq p (point-min)) (let ((m (org-roam-capture-find-or-create-olp olp))) (goto-char m))) @@ -593,7 +593,7 @@ it." (or (org-roam-node-file org-roam-capture--node) (thread-first path - (org-roam-capture--fill-template t) + (org-roam-capture--fill-template) (string-trim) (expand-file-name org-roam-directory)))) @@ -618,7 +618,7 @@ you can catch it with `condition-case'." (org-with-wide-buffer (goto-char start) (dolist (heading olp) - (setq heading (org-roam-capture--fill-template heading t)) + (setq heading (org-roam-capture--fill-template heading)) (let ((re (format org-complex-heading-regexp-format (regexp-quote heading))) (cnt 0)) @@ -752,43 +752,40 @@ This function is to be called in the Org-capture finalization process." (insert link))))))) ;;;; Processing of the capture templates -(defun org-roam-capture--fill-template (template &optional org-capture-p newline) +(defun org-roam-capture--fill-template (template &optional ensure-newline) "Expand TEMPLATE and return it. -It expands ${var} occurrences in TEMPLATE. When ORG-CAPTURE-P, -also run Org-capture's template expansion. -If NEWLINE, ensure that the template returned ends with a newline." - (setq template (org-roam-format-template - template - (lambda (key default-val) - (let ((fn (intern key)) - (node-fn (intern (concat "org-roam-node-" key))) - (ksym (intern (concat ":" key)))) - (cond - ((fboundp fn) - (funcall fn org-roam-capture--node)) - ((fboundp node-fn) - (funcall node-fn org-roam-capture--node)) - ((plist-get org-roam-capture--info ksym) - (plist-get org-roam-capture--info ksym)) - (t (let ((r (read-from-minibuffer (format "%s: " key) default-val))) - (plist-put org-roam-capture--info ksym r) - r))))))) - ;; WARNING: - ;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant - ;; template does not start with any whitespace, and only ends with a single newline - ;; - ;; In most cases where we rely on `org-capture-fill-template' to populate non-org-capture-related templates, - ;; (e.g. in OLPs), we strip the final newline, obtaining a template that seems to be string-trimmed. - ;; - ;; This means that if the original passed template has newlines, and ORG-CAPTURE-P is true, then the extra - ;; whitespace specified in the template will be ignored. - (when org-capture-p +It expands ${var} occurrences in TEMPLATE, and then runs +org-capture's template expansion. +When ENSURE-NEWLINE, always ensure there's a newline behind." + (let ((template-whitespace-content (org-roam-whitespace-content template))) (setq template - (replace-regexp-in-string "\n$" "" (org-capture-fill-template template)))) - (when (and newline - (not (string-suffix-p "\n" template))) - (setq template (concat template "\n"))) - template) + (org-roam-format-template + template + (lambda (key default-val) + (let ((fn (intern key)) + (node-fn (intern (concat "org-roam-node-" key))) + (ksym (intern (concat ":" key)))) + (cond + ((fboundp fn) + (funcall fn org-roam-capture--node)) + ((fboundp node-fn) + (funcall node-fn org-roam-capture--node)) + ((plist-get org-roam-capture--info ksym) + (plist-get org-roam-capture--info ksym)) + (t (let ((r (read-from-minibuffer (format "%s: " key) default-val))) + (plist-put org-roam-capture--info ksym r) + r))))))) + ;; WARNING: + ;; `org-capture-fill-template' fills the template, but post-processes whitespace such that the resultant + ;; template does not start with any whitespace, and only ends with a single newline + ;; + ;; Instead, we restore the whitespace in the original template. + (setq template (replace-regexp-in-string "\n$" "" (org-capture-fill-template template))) + (when (and ensure-newline + (string-equal template-whitespace-content "")) + (setq template-whitespace-content "\n")) + (setq template (concat template template-whitespace-content)) + template)) (defun org-roam-capture--convert-template (template &optional props) "Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax. diff --git a/org-roam-utils.el b/org-roam-utils.el index 8d30de0..a5c30ea 100644 --- a/org-roam-utils.el +++ b/org-roam-utils.el @@ -69,6 +69,15 @@ Like `string-equal', but case-insensitive." (or (string-equal s1 s2) (string-equal (downcase s1) (downcase s2))))) +(defun org-roam-whitespace-content (s) + "Return the whitespace content at the end of S." + (with-temp-buffer + (let ((c 0)) + (insert s) + (skip-chars-backward " \t\n") + (buffer-substring-no-properties + (point) (point-max))))) + (defun org-roam-strip-comments (s) "Strip Org comments from string S." (with-temp-buffer diff --git a/tests/test-org-roam-capture.el b/tests/test-org-roam-capture.el new file mode 100644 index 0000000..34f37bb --- /dev/null +++ b/tests/test-org-roam-capture.el @@ -0,0 +1,51 @@ +;;; test-org-roam-capture.el --- Tests for Org-roam -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Jethro Kuan + +;; Author: Jethro Kuan +;; Package-Requires: ((buttercup)) + +;; 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 of the License, 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 this program. If not, see . + +;;; Commentary: +;;; Code: + +(require 'buttercup) +(require 'org-roam) + +(describe "org-roam-capture--fill-template" + (it "fills template without newline" + (expect + (org-roam-capture--fill-template "foo") + :to-equal "foo")) + + (it "fills template ensuring newline" + (expect + (org-roam-capture--fill-template "foo" 'ensure-newline) + :to-equal "foo\n")) + + (it "fills template with newline" + (expect + (org-roam-capture--fill-template "foo\n") + :to-equal "foo\n")) + + (it "fills template with two newlines" + (expect + (org-roam-capture--fill-template "foo\n\n") + :to-equal "foo\n\n") + (expect + (org-roam-capture--fill-template "foo\n\t\n") + :to-equal "foo\n\t\n"))) + +(provide 'test-org-roam-capture) diff --git a/tests/test-org-roam-utils.el b/tests/test-org-roam-utils.el new file mode 100644 index 0000000..ae85f7d --- /dev/null +++ b/tests/test-org-roam-utils.el @@ -0,0 +1,39 @@ +;;; test-org-roam-utils.el --- Tests for Org-roam -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Jethro Kuan + +;; Author: Jethro Kuan +;; Package-Requires: ((buttercup)) + +;; 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 of the License, 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 this program. If not, see . + +;;; Commentary: +;;; Code: + +(require 'buttercup) +(require 'org-roam) + +(describe "org-roam-whitespace-content" + (it "extracts whitespace correctly" + (expect + (org-roam-whitespace-content "foo") + :to-equal "") + (expect + (org-roam-whitespace-content "foo\n") + :to-equal "\n") + (expect + (org-roam-whitespace-content "foo\n\t\n") + :to-equal "\n\t\n"))) + +(provide 'test-org-roam-utils)