emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/denote 00c4e70dfa 5/5: Add denote-templates user option


From: ELPA Syncer
Subject: [elpa] externals/denote 00c4e70dfa 5/5: Add denote-templates user option
Date: Sun, 7 Aug 2022 01:57:29 -0400 (EDT)

branch: externals/denote
commit 00c4e70dfac0fec647cf6961340539cc0823b3ed
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>

    Add denote-templates user option
---
 README.org | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 denote.el  |  81 ++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 174 insertions(+), 10 deletions(-)

diff --git a/README.org b/README.org
index 16d89160af..1eab8bbcbe 100644
--- a/README.org
+++ b/README.org
@@ -133,11 +133,14 @@ Obligations, Tasks, and Engagements.
 #+findex: denote-org-capture
 #+findex: denote-date
 #+findex: denote-subdirectory
+#+findex: denote-template
 There are five ways to write a note with Denote: invoke the ~denote~,
-~denote-type~, ~denote-date~, ~denote-subdirectory~ commands, or
-leverage the ~org-capture-templates~ by setting up a template which
-calls the function ~denote-org-capture~.  We explain all of those in the
-subsequent sections.
+~denote-type~, ~denote-date~, ~denote-subdirectory~, ~denote-template~
+commands, or leverage the ~org-capture-templates~ by setting up a
+template which calls the function ~denote-org-capture~.  We explain all
+of those in the subsequent sections.
+
+[ The ~denote-template~ is part of {{{development-version}}} ]
 
 ** Standard note creation
 :PROPERTIES:
@@ -212,6 +215,12 @@ The value is a list of symbols, which includes any of the 
following:
   like 2022-06-16 or a date plus time: 2022-06-16 14:30.  Without the
   =date= prompt, the ~denote~ command uses the ~current-time~.
 
+- =template=: Prompts for a KEY among the ~denote-templates~.  The value
+  of that KEY is used to populate the new note with content, which is
+  added after the front matter ([[#h:f635a490-d29e-4608-9372-7bd13b34d56c][The 
denote-templates option]]).
+
+  [ The =template= is part of {{{development-version}}} ]
+
 The prompts occur in the given order.
 
 If the value of this user option is nil, no prompts are used.  The
@@ -240,6 +249,73 @@ interactive actions that do not change the default 
behaviour of the
 ~denote-type~, ~denote-subdirectory~, ~denote-date~.  They are described
 in the subsequent section 
([[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note 
creation]]).
 
+*** The ~denote-templates~ option
+:PROPERTIES:
+:CUSTOM_ID: h:f635a490-d29e-4608-9372-7bd13b34d56c
+:END:
+
+[ Part of {{{development-version}}} ]
+
+#+vindex: denote-templates
+The user option ~denote-templates~ is an alist of content templates for
+new notes.  A template is arbitrary text that Denote will add to a newly
+created note right below the front matter.
+
+Templates are expressed as a =(KEY . STRING)= association.
+
+- The =KEY= is the name which identifies the template.  It is an
+  arbitrary symbol, such as =report=, =memo=, =statement=.
+
+- The =STRING= is ordinary text that Denote will insert as-is.  It can
+  contain newline characters to add spacing.  Below we show some
+  concrete examples.
+
+The user can choose a template either by invoking the command
+~denote-template~ or by changing the user option ~denote-prompts~ to
+always prompt for a template when calling the ~denote~ command.
+
+[[#h:f9204f1f-fcee-49b1-8081-16a08a338099][The denote-prompts option]].
+
+[[#h:887bdced-9686-4e80-906f-789e407f2e8f][Convenience commands for note 
creation]].
+
+Templates can be written directly as one large string.  For example (the
+=\n= character is read as a newline):
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      '((report . "* Some heading\n\n* Another heading")
+        (memo . "* Some heading
+
+,* Another heading
+
+")))
+#+end_src
+
+Long strings may be easier to type but interpret indentation literally.
+Also, they do not scale well.  A better way is to use some Elisp code to
+construct the string.  This would typically be the ~concat~ function,
+which joins multiple strings into one.  The following is the same as the
+previous example:
+
+#+begin_src emacs-lisp
+(setq denote-templates
+      `((report . "* Some heading\n\n* Another heading")
+        (memo . ,(concat "* Some heading"
+                         "\n\n"
+                         "* Another heading"
+                         "\n\n"))))
+#+end_src
+
+Notice that to evaluate a function inside of an alist we use the
+backtick to quote the alist (NOT the straight quote) and then prepend a
+comma to the expression that should be evaluated.  The ~concat~ form
+here is not sensitive to indentation, so it is easier to adjust for
+legibility.
+
+DEV NOTE: We do not provide more examples at this point, though feel
+welcome to ask for help if the information provided herein is not
+sufficient.  We shall expand the manual accordingly.
+
 *** Convenience commands for note creation
 :PROPERTIES:
 :CUSTOM_ID: h:887bdced-9686-4e80-906f-789e407f2e8f
@@ -292,6 +368,20 @@ commands for note creation:
   The ~denote-create-note-in-subdirectory~ is a more descriptive alias
   of ~denote-subdirectory~.
 
+  [ Templates are part of {{{development-version}}} ]
+
++ Create note and add a template :: The ~denote-template~ command
+  creates a new note and inserts the specified template below the front
+  matter ([[#h:f635a490-d29e-4608-9372-7bd13b34d56c][The denote-templates 
option]]).  Available candidates for
+  templates are specified in the user option ~denote-templates~.
+
+  This is equivalent to calling ~denote~ when ~denote-prompts~ is
+  set to ='(template title keywords)=.
+
+  #+findex: denote-create-note-with-template
+  The ~denote-create-note-with-template~ is an alias of the command
+  ~denote-template~, meant to help with discoverability.
+
 ** Create note using Org capture
 :PROPERTIES:
 :CUSTOM_ID: h:656c70cd-cf9a-4471-a0b5-4f0aaf60f881
@@ -1673,6 +1763,10 @@ Everything is in place to set up the package.
 (setq denote-file-type nil) ; Org is the default, set others here
 (setq denote-prompts '(title keywords))
 
+;; Read this manual for how to specify `denote-templates'.  We do not
+;; include an example here to avoid potential confusion.
+
+
 ;; We allow multi-word keywords by default.  The author's personal
 ;; preference is for single-word keywords for a more rigid workflow.
 (setq denote-allow-multi-word-keywords t)
@@ -1719,6 +1813,7 @@ Everything is in place to set up the package.
   (define-key map (kbd "C-c n N") #'denote-type)
   (define-key map (kbd "C-c n d") #'denote-date)
   (define-key map (kbd "C-c n s") #'denote-subdirectory)
+  (define-key map (kbd "C-c n t") #'denote-template)
   ;; If you intend to use Denote with a variety of file types, it is
   ;; easier to bind the link-related commands to the `global-map', as
   ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
diff --git a/denote.el b/denote.el
index 0a024ac263..589eaea1de 100644
--- a/denote.el
+++ b/denote.el
@@ -204,6 +204,10 @@ The value is a list of symbols, which includes any of the 
following:
   Without the `date' prompt, the `denote' command uses the
   `current-time'.
 
+- `template': Prompts for a KEY among `denote-templates'.  The
+  value of that KEY is used to populate the new note with
+  content, which is added after the front matter.
+
 The prompts occur in the given order.
 
 If the value of this user option is nil, no prompts are used.
@@ -233,6 +237,7 @@ behaviour of the `denote' command, users can invoke these
 convenience commands: `denote-type', `denote-subdirectory',
 `denote-date'."
   :group 'denote
+  :package-version '(denote . "0.5.0")
   :link '(info-link "(denote) The denote-prompts option")
   :type '(radio (const :tag "Use no prompts" nil)
                 (set :tag "Available prompts" :greedy t
@@ -240,7 +245,8 @@ convenience commands: `denote-type', `denote-subdirectory',
                      (const :tag "Keywords" keywords)
                      (const :tag "Date" date)
                      (const :tag "File type extension" file-type)
-                     (const :tag "Subdirectory" subdirectory))))
+                     (const :tag "Subdirectory" subdirectory)
+                     (const :tag "Template" template))))
 
 (defcustom denote-sort-keywords t
   "Whether to sort keywords in new files.
@@ -313,6 +319,29 @@ are described in the doc string of `format-time-string'."
   :package-version '(denote . "0.2.0")
   :group 'denote)
 
+(defcustom denote-templates nil
+  "Alist of content templates for new notes.
+A template is arbitrary text that Denote will add to a newly
+created note right below the front matter.
+
+Templates are expressed as a (KEY . STRING) association.
+
+- The KEY is the name which identifies the template.  It is an
+  arbitrary symbol, such as `report', `memo', `statement'.
+
+- The STRING is ordinary text that Denote will insert as-is.  It
+  can contain newline characters to add spacing.  The manual of
+  Denote contains examples on how to use the `concat' function,
+  beside writing a generic string.
+
+The user can choose a template either by invoking the command
+`denote-template' or by changing the user option `denote-prompts'
+to always prompt for a template when calling the `denote'
+command."
+  :type '(alist :key-type symbol :value-type string)
+  :package-version '(denote . "0.5.0")
+  :group 'denote)
+
 ;;;; Main variables
 
 ;; For character classes, evaluate: (info "(elisp) Char Classes")
@@ -906,7 +935,7 @@ where the former does not read dates without a time 
component."
 ;;;;; The `denote' command and its prompts
 
 ;;;###autoload
-(defun denote (&optional title keywords file-type subdirectory date)
+(defun denote (&optional title keywords file-type subdirectory date template)
   "Create a new note with the appropriate metadata and file name.
 
 When called interactively, the metadata and file name are prompted
@@ -929,16 +958,21 @@ When called from Lisp, all arguments are optional.
 
 - DATE is a string representing a date like 2022-06-30 or a date
   and time like 2022-06-16 14:30.  A nil value or an empty string
-  is interpreted as the `current-time'."
+  is interpreted as the `current-time'.
+
+- TEMPLATE is a symbol which represents the key of a cons cell in
+  the user option `denote-template'.  The value of that key is
+  inserted to the newly created buffer after the front matter."
   (interactive
-   (let ((args (make-vector 5 nil)))
+   (let ((args (make-vector 6 nil)))
      (dolist (prompt denote-prompts)
        (pcase prompt
          ('title (aset args 0 (denote--title-prompt)))
          ('keywords (aset args 1 (denote--keywords-prompt)))
          ('file-type (aset args 2 (denote--file-type-prompt)))
          ('subdirectory (aset args 3 (denote--subdirs-prompt)))
-         ('date (aset args 4 (denote--date-prompt)))))
+         ('date (aset args 4 (denote--date-prompt)))
+         ('template (aset args 5 (denote--template-prompt)))))
      (append args nil)))
   (let* ((file-type (denote--file-type-symbol (or file-type denote-file-type)))
          (date (if (or (null date) (string-empty-p date))
@@ -947,9 +981,14 @@ When called from Lisp, all arguments are optional.
          (id (format-time-string denote--id-format date))
          (directory (if (denote--dir-in-denote-directory-p subdirectory)
                         (file-name-as-directory subdirectory)
-                      (denote-directory))))
+                      (denote-directory)))
+         (template (if (stringp template) template (alist-get template 
denote-templates))))
     (denote--barf-duplicate-id id)
     (denote--prepare-note (or title "") keywords date id directory file-type)
+    (when template
+      (with-current-buffer (get-file-buffer denote-last-path)
+        (goto-char (point-max))
+        (insert template)))
     (denote--keywords-add-to-history keywords)))
 
 (defvar denote--title-history nil
@@ -1005,6 +1044,19 @@ here for clarity."
          (dirs (push root subdirs)))
     (denote--subdirs-completion-table dirs)))
 
+(defvar denote--template-history nil
+  "Minibuffer history of `denote--template-prompt'.")
+
+(defun denote--template-prompt ()
+  "Prompt for template KEY from `denote-templates'."
+  (let ((templates denote-templates))
+    (alist-get
+     (intern
+      (completing-read
+       "Select template KEY: " (mapcar #'car templates)
+       nil t nil 'denote--template-history))
+     templates)))
+
 ;;;;; Convenience commands as `denote' variants
 
 (defalias 'denote-create-note (symbol-function 'denote))
@@ -1054,6 +1106,23 @@ set to \\='(subdirectory title keywords)."
 
 (defalias 'denote-create-note-in-subdirectory (symbol-function 
'denote-subdirectory))
 
+;;;###autoload
+(defun denote-template ()
+  "Create note while prompting for a template.
+
+Available candidates include the keys in the `denote-templates'
+alist.  The value of the selected key is inserted in the newly
+created note after the front matter.
+
+This is equivalent to calling `denote' when `denote-prompts' is
+set to \\='(template title keywords)."
+  (declare (interactive-only t))
+  (interactive)
+  (let ((denote-prompts '(template title keywords)))
+    (call-interactively #'denote)))
+
+(defalias 'denote-create-note-with-template (symbol-function 'denote-template))
+
 ;;;; Note modification
 
 ;;;;; Common helpers for note modifications



reply via email to

[Prev in Thread] Current Thread [Next in Thread]