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

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

[elpa] externals/denote d5b62c4e58 220/355: Add denote-date command (not


From: ELPA Syncer
Subject: [elpa] externals/denote d5b62c4e58 220/355: Add denote-date command (notes for past date)
Date: Sun, 26 Jun 2022 23:58:26 -0400 (EDT)

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

    Add denote-date command (notes for past date)
    
    Thanks to user svnsbck for suggesting the idea in issue 15 over at the
    GitHub repo: <https://github.com/protesilaos/denote/issues/15>.
---
 README.org |  30 +++++++++++++----
 denote.el  | 107 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 110 insertions(+), 27 deletions(-)

diff --git a/README.org b/README.org
index e324a12fbf..192d5bfa7c 100644
--- a/README.org
+++ b/README.org
@@ -216,9 +216,11 @@ holds the relevant value.  In simple terms:
 #+findex: denote
 #+findex: denote-type
 #+findex: denote-org-capture
-There are three ways to write a note with Denote: invoke the ~denote~,
-or ~denote-type~ commands, or leverage the ~org-capture-templates~ by
-setting up a template which calls the function ~denote-org-capture~.
+#+findex: denote-date
+There are four ways to write a note with Denote: invoke the ~denote~,
+~denote-type~, ~denote-date~ commands, or leverage the
+~org-capture-templates~ by setting up a template which calls the
+function ~denote-org-capture~.
 
 In the first case, all that is needed is to run ~denote~.  It will
 prompt for a title.  Once it is supplied, the command will ask for
@@ -248,6 +250,19 @@ file type to use as a local value for ~denote-file-type~.  
In practical
 terms, this lets you produce, say, a note in Markdown even though you
 normally write in Org ([[#h:f34b172b-3440-446c-aec1-bf818d0aabfe][Notes in 
multiple file types]]).
 
+Similarly, the ~denote-date~ command accepts the same =TITLE= and
+=KEYWORDS= arguments, though it starts by asking for a date.  Normally,
+Denote use the current date and time to construct an identifier, but
+~denote-date~ allows the user to specify any date+time combination.  The
+input for the =DATE= argument is like =2022-06-16= or =2022-06-16
+14:30=.  When the time is omitted, it is interpreted as =00:00=.
+
+Since the ability to insert a date may result in duplicate identifiers,
+Denote takes care to abort the operation if such an identity is
+established (e.g. when you use ~denote-date~ with =2022-06-16= twice, it
+will generate the same identifier of =20220616T000000=).  The user must
+thus call the ~denote-date~ command again and provide a unique value.
+
 For integration with ~org-capture~, the user must first add the relevant
 template.  Such as:
 
@@ -294,10 +309,12 @@ the ~denote-org-capture-specifiers~.
 
 #+findex: denote-create-note
 #+findex: denote-create-note-using-type
+#+findex: denote-create-note-using-date
 For convencience, the ~denote~ command has a ~denote-create-note~ alias.
-Same for ~denote-type~: ~denote-create-note-using-type~.  The purpose of
-these aliases is to provide alternative, more descriptive names of select
-commands to aid with discoverability.
+Same for ~denote-type~ which is ~denote-create-note-using-type~ and
+~denote-date~ that has ~denote-create-note-using-date~.  The purpose of
+these aliases is to provide alternative, more descriptive names of
+select commands to aid with discoverability.
 
 * Renaming files
 :PROPERTIES:
@@ -1137,6 +1154,7 @@ Everything is in place to set up the package.
   (define-key map (kbd "C-c n j") #'my-denote-journal) ; our custom command
   (define-key map (kbd "C-c n n") #'denote)
   (define-key map (kbd "C-c n N") #'denote-type)
+  (define-key map (kbd "C-c n d") #'denote-date)
   ;; 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 35447baccb..bed891d36c 100644
--- a/denote.el
+++ b/denote.el
@@ -504,42 +504,51 @@ With optional ID, use it else format the current time."
 
 ;; Adapted from `org-hugo--org-date-time-to-rfc3339' in the `ox-hugo'
 ;; package: <https://github.com/kaushalmodi/ox-hugo>.
-(defun denote--date-rfc3339 ()
-  "Format date using the RFC3339 specification."
+(defun denote--date-rfc3339 (&optional date)
+  "Format date using the RFC3339 specification.
+With optional DATE, use it else use the current one."
   (replace-regexp-in-string
    "\\([0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\)\\'" "\\1:\\2"
-   (format-time-string "%FT%T%z")))
+   (format-time-string "%FT%T%z" date)))
 
-(defun denote--date-org-timestamp ()
-  "Format date using the Org inactive timestamp notation."
-  (format-time-string "[%F %a %R]"))
+(defun denote--date-org-timestamp (&optional date)
+  "Format date using the Org inactive timestamp notation.
+With optional DATE, use it else use the current one."
+  (format-time-string "[%F %a %R]" date))
 
-(defun denote--date-iso-8601 ()
-  "Format date according to ISO 8601 standard."
-  (format-time-string "%F"))
+(defun denote--date-iso-8601 (&optional date)
+  "Format date according to ISO 8601 standard.
+With optional DATE, use it else use the current one."
+  (format-time-string "%F" date))
 
-(defun denote--date ()
-  "Expand the date for a new note's front matter."
+(defun denote--date (&optional date)
+  "Expand the date for a new note's front matter.
+With optional DATE, use it else use the current one."
   (let ((format denote-front-matter-date-format))
     (cond
      ((stringp format)
-      (format-time-string format))
+      (format-time-string format date))
      ((or (eq denote-file-type 'markdown-toml)
           (eq denote-file-type 'markdown-yaml))
-      (denote--date-rfc3339))
+      (denote--date-rfc3339 date))
      ((eq format 'org-timestamp)
-      (denote--date-org-timestamp))
-     (t (denote--date-iso-8601)))))
+      (denote--date-org-timestamp date))
+     (t (denote--date-iso-8601 date)))))
 
-(defun denote--prepare-note (title keywords &optional path)
+(defun denote--prepare-note (title keywords &optional path date id)
   "Use TITLE and KEYWORDS to prepare new note file.
-Use optional PATH, else create it with `denote--path'."
-  (let* ((p (or path (denote--path title keywords)))
-         (default-directory denote-directory)
+Use optional PATH, else create it with `denote--path'.  When PATH
+is provided, refrain from writing to a buffer (useful for org
+capture).
+
+Optional DATE is passed to `denote--date', while optional ID is
+used to construct the path's identifier."
+  (let* ((default-directory denote-directory)
+         (p (or path (denote--path title keywords default-directory id)))
          (buffer (unless path (find-file p)))
          (header (denote--file-meta-header
-                  title (denote--date) keywords
-                  (format-time-string denote--id-format))))
+                  title (denote--date date) keywords
+                  (format-time-string denote--id-format date))))
     (unless path
       (with-current-buffer buffer (insert header))
       (setq denote-last-buffer buffer))
@@ -611,5 +620,61 @@ When called from Lisp the FILETYPE must be a symbol."
 
 (defalias 'denote-create-note-using-type (symbol-function 'denote-type))
 
+(defvar denote--date-history nil
+  "Minibuffer history of `denote--date-prompt'.")
+
+(defun denote--date-prompt ()
+  "Prompt for date."
+  (read-string
+   "DATE and TIME for note (e.g. 2022-06-16 14:30): "
+   nil 'denote--date-history))
+
+(defun denote--valid-date (date)
+  "Return DATE if parsed by `date-to-time', else signal error."
+  (date-to-time date))
+
+;; This should only be relevant for `denote-date', otherwise the
+;; identifier is always unique (we trust that no-one writes multiple
+;; notes within fractions of a second).
+(defun denote--id-exists-p (identifier no-check-current)
+  "Return non-nil if IDENTIFIER already exists.
+NO-CHECK-CURRENT passes the appropriate flag to
+`denote--directory-files-matching-regexp'."
+  (denote--directory-files-matching-regexp identifier no-check-current))
+
+(defun denote--barf-duplicate-id (identifier)
+  "Throw a user-error if IDENTIFIER already exists else return t."
+  (if (denote--id-exists-p identifier :no-check-current)
+      (user-error "`%s' already exists; aborting new note creation" identifier)
+    t))
+
+;;;###autoload
+(defun denote-date (date title keywords)
+  "Like `denote', but create new note for given DATE.
+
+DATE can either be something like 2022-06-16 or that plus time:
+2022-06-16 14:30.
+
+The hour can be omitted, in which case it is interpreted as
+00:00.  Beware that you might create files with non-unique
+identifiers if they both have the same date and time.  In such a
+case, Denote will refrain from creating the new note.  Try with
+another DATE value where, for instance, a different time is
+specified.
+
+The TITLE and KEYWORDS arguments are the same as with `denote'."
+  (interactive
+   (list
+    (denote--date-prompt)
+    (denote--title-prompt)
+    (denote--keywords-prompt)))
+  (when-let ((d (denote--valid-date date))
+             (id (format-time-string denote--id-format d))
+             ((denote--barf-duplicate-id id)))
+    (denote--prepare-note title keywords nil d id)
+    (denote--keywords-add-to-history keywords)))
+
+(defalias 'denote-create-note-using-date (symbol-function 'denote-date))
+
 (provide 'denote)
 ;;; denote.el ends here



reply via email to

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