Giter VIP home page Giter VIP logo

doct's Introduction

DOCT: Declarative Org Capture Templates

https://melpa.org/packages/doct-badge.svg

doct is a function that provides an alternative, declarative syntax for describing Org capture templates.

tl;dr

(defun my-org-template-hook ()
  (when (string= (org-capture-get :key t) "p1")
    (message "\"First Child\" selected.")))

(add-hook 'org-capture-mode-hook 'my-org-template-hook)

(setq org-capture-templates
      '(("p" "Parent")
        ("p1" "First Child"  entry (file+headline "~/example.org" "One")
         "* TODO %^{Description} \n:PROPERTIES:\n:Created: %U\n:END:\n%?"
         :prepend t)
        ("p2" "Second Child" entry (file+headline "~/example.org" "Two")
         "* NEXT %^{Description} \n:PROPERTIES:\n:Created: %U\n:END:\n%?"
         :prepend t)
        ("p3" "Third Child"  entry (file+headline "~/example.org" "Three")
         "* MAYBE %^{Description} \n:PROPERTIES:\n:Created: %U\n:END:\n%?"
         :prepend t)))

becomes:

(setq org-capture-templates
      (doct '(("Parent" :keys "p"
               :file "~/example.org"
               :prepend t
               :template ("* %{todo-state} %^{Description}"
                          ":PROPERTIES:"
                          ":Created: %U"
                          ":END:"
                          "%?")
               :children (("First Child"  :keys "1"
                           :headline   "One"
                           :todo-state "TODO"
                           :hook (lambda () (message "\"First Child\" selected.")))
                          ("Second Child" :keys "2"
                           :headline   "Two"
                           :todo-state "NEXT")
                          ("Third Child"  :keys "3"
                           :headline   "Three"
                           :todo-state "MAYBE"))))))

Releases

3.2.0

  • add doct-add-to function Add support for “here” target (Org 9.7)

3.1.0

3.0.0

  • drop support for recursive %{keyword} expansion.

2.0.0

  • drop support for %doct(KEYWORD) syntax. Replaced with %{keyword}
  • doct-get now accepts an optional parameter to determine whether to query org-capture-plist or org-capture-current-plist.
  • adopt semver

Contents

Installation

MELPA

Try it with the straight package manager:

(straight-use-package 'doct)

or use-package:

(use-package doct
  :ensure t
  ;;recommended: defer until calling doct
  :commands (doct))

Manual

Download doct and make sure it is in your load-path. Require it in your init file.

(require 'doct)

Documentation

doct

(doct declarations)

doct expects a declaration or a list of declarations as its sole argument and converts it into a list of `org-capture-templates`. Each declaration is either a child, parent, or group.

Child

A child declaration must have:

  • a name
  • a :keys string
  • a template type
  • a target
  • a template

and may also have:

  • hook functions defined with the hook keywords
  • contexts declared via the :contexts keyword
  • additional :KEY VAL arguments

Parent

A parent declaration must have:

  • a name
  • a :keys string
  • a list of :children

and may also have additional properties inherited by its children.

Group

A group is a special kind of parent declaration. Its children inherit its properties, but it is not added to the template selection menu. Its name must be the :group keyword. It may optionally have a descriptive string for the value of :group. It must not have a :keys value.

(doct '(("Work" :keys "w" :file "~/org/work.org" :children
         ((:group "Clocked" :clock-in t :children
                  (("Phone Call" :keys "p" :template "* Phone call with %?")
                   ("Meeting"    :keys "m" :template "* Meeting with %?")))
          ("Browsing" :keys "b" :template "* Browsing %x")))))

returns:

(("w" "Work")
 ("wp" "Phone Call" entry (file "~/org/work.org") "* Phone call with %?" :clock-in t)
 ("wm" "Meeting"    entry (file "~/org/work.org") "* Meeting with %?"    :clock-in t)
 ("wb" "Browsing"   entry (file "~/org/work.org") "* Browsing %x"))

Name & Keys

Every declaration must define a name. Unless it is a group , it must also define a :keys value. The name is the first value in the declaration. The :keys keyword defines the keys to access the template from the capture menu.

(doct '(("example" :keys "e" ...)))

returns:

(("e" "example" ...))

Children

The :children keyword defines a parent’s children. Its value may be a single declaration or a list of declarations. The parent’s :keys prefix each child’s :keys.

(doct '(("parent" :keys "p"
         :children
         (("child" :keys "c"
           :children
           (("grandchild" :keys "g"
             :file ""
             :type plain
             :template "test")))))))

returns:

(("p" "parent") ("pc" "child") ("pcg" "grandchild" plain (file "") "test"))

Inherited Properties

A child inherits its ancestors’ properties. It may optionally override an inherited property by specifying that property directly.

For example:

(doct '(("Grandparent" :keys "g"
         :file "example.org"
         :children ("Parent" :keys "p"
                    :children ("Child" :keys "c")))))

The “Child” template inherits its :file property from the “Grandparent” declaration. The “Parent” declaration could override this value:

(doct '(("Grandparent" :keys "g"
         :file "example.org"
         :children ("Parent" :keys "p"
                    :file "overridden.org"
                    :children ("Child" :keys "c")))))

And the “Child” would have its :file property set to “overridden.org”.

Type

The :type keyword defines the template’s entry type and accepts the following symbols:

entry
An Org node with a headline. The template becomes a child of the target entry or a top level entry.
item
A plain list item, placed in the first plain list at the target location.
checkitem
A checkbox item. Same as plain list item only it uses a different default template.
table-line
A new line in the first table at target location.
plain
Text inserted as is.

doct-default-entry-type defines the entry type when the :type keyword is not provided.

For example, with doct-default-entry-type set to entry (the default):

(doct '(("example"
         :keys "e"
         :type entry
         :file "")))

And

(doct '(("example"
         :keys "e"
         :file "")))

Both return:

(("e" "example" entry (file "") nil))

Target

The target defines the location of the inserted template text.

The first keyword declared in the following group exclusively sets the target. The :file keyword is not necessary for these.

:id “id of existing Org entry”
File as child of this entry, or in the body of the entry (see org-id-get-create and the Org Mode Manual)
:clock t
File to the currently clocked entry
:function (lambda () ;visit file and move point to desired location…)
This keyword is exclusive when used without the :file keyword. It is responsible for finding the proper file and location to insert the capture item. If :file defines a target file, then the function is only responsible for moving point to the desired location within that file.
(doct '(("example"
         :keys "e"
         :type entry
         :clock t
         ;;ignored because clock is first
         :function (lambda () (ignore))
         ;;also ignored
         :id "1")))

returns:

(("e" "example" entry (clock) nil))

The :file keyword defines the target file for the capture template. It may be:

  • a string:
(doct ... :file "/path/to/target.org")
;;empty string defaults to `org-default-notes-file'
(doct ... :file "")
  • a function:
;;lambda
(doct ... :file (lambda () (concat (read-string "Org Capture Path: ") ".org")))
;;or a function symbol
(doct ... :file my/get-file-path)
  • or a variable:
(doct ... :file my/file-path)

The following keywords refine the target file location:

:headline “node headline”
File under unique heading in target file.
:olp (“Level 1 heading” “Level 2 heading”…)

Define the full outline in the target file.

:datetree nil|t
Requires use of the :file keyword. If :datetree has a non-nil value, create a date tree for today’s date. If :olp is given, the date tree is added under that heading path. Use a non-nil :time-prompt property to prompt for a different date. Set the :tree-type property to the symbol week create a week tree instead of the default month tree.
:regexp “regexp describing location”

File to the entry matching regexp in target file

:function location-finding-function

If used in addition to the :file keyword, the value should be a function that finds the desired location in that file. If used as an exclusive keyword (see above), the function must locate both the target file and move point to the desired location.

Template

The :template keyword defines the template for creating the capture item. It may be either a string, list of strings, or a function. doct joins the list with new lines. A function must return the template text.

(doct '((... :template ("Test" "One" "Two"))))

returns:

((... "Test\nOne\nTwo"))

The :template-file keyword defines a file containing the text of the template. For example:

(doct '((... :template-file "~/org/templates/template.txt")))

will use the text of template.txt as the template string.

The first keyword declared overrides any additional template declarations.

Additional options

Key-value pairs define additional options.

(doct '((... :immediate-finish t)))

returns:

((... :immediate-finish t))

see the Org Mode Manual for a full list of additional options.

Custom data

doct stores unrecognized keywords on the template’s org-capture-plist as members of the doct-custom plist. This makes a template’s metadata accessible during capture. See %{KEYWORD} Expansion for details on using that data.

The :custom keyword accepts a plist. doct copies the plist’s values to the doct-custom plist. This is only necessary if you wish to use a keyword which doct already uses.

For example:

(doct '(("Music Gear" :keys "m" :file ""
         :custom (:keys "Moog"))))

returns:

(#1="m" #2="Music Gear" entry (file #3="") nil
    :doct (#2# :keys #1# :file #3# :custom #4=(:keys "Moog") :doct-custom #4#))))

%{KEYWORD} Expansion

A declaration :template may include a keyword’s value during capture. The syntax is similar to other, built-in “%-escapes”. %{KEYWORD} will insert the value declared with :KEYWORD in the declaration.

For example, with:

(doct '(("Parent" :keys "p"
         :file ""
         :template "* %{todo-state} %?"
         :children (("One" :keys "1" :todo-state "TODO")
                    ("Two" :keys "2" :todo-state "IDEA")))))

Each child template has its :todo-state value expanded in the inherited :template.

Values should be strings, functions or nil.

(doct '(("%{string}" :keys "s" :type plain :file ""
         :string "string"
         :template "%{string}")))

Is replaced with:

"string"
(doct '(("%{fn}" :keys "f" :type plain :file ""
         :fn (lambda () "string returned from function")
         :template "%{fn}")))

Is replaced with:

"string returned from function"
(doct '(("%{nil}" :keys "f" :type plain :file ""
         :nil nil
         :template "%{nil}")))

Is replaced with the empty string

""

Custom keywords take precedence over other declaration keywords. For example, with:

(doct '(("Music Gear" :keys "m" :file "" :type plain
         :custom (:keys "Moog")
         :template "%{keys}")))

The “Music Gear” template expands to “Moog” instead of “m”. Nil values expand to an empty string.

Hooks

Adding the following hook keywords in a declaration adds its value to the appropriate org-capture hook. The value may be a function or a variable.

:hook function
org-capture-mode-hook

Runs FUNCTION when entering the org-capture-mode minor mode.

:prepare-finalize function
org-capture-prepare-finalize-hook

Runs FUNCTION before the finalization starts. The capture buffer is current and narrowed.

:before-finalize function
org-capture-before-finalize-hook

Runs FUNCTION right before a capture process finalizes. The capture buffer is still current and widened to the entire buffer.

:after-finalize function
org-capture-after-finalize-hook
Runs FUNCTION right after a capture process finalizes. Suitable for window cleanup.

For example:

(doct `(("example"
         :keys "e"
         :file ""
         :hook ,(defun my/fn  ()
                  (ignore)))))

runs my/fn during the org-capture-mode-hook when selecting the “example” template.

Contexts

The :contexts keyword defines contextual rules for a template. Its value may be a single contextual rule or a list of rules. The following keywords are available to create contextual rules:

:in-buffer regexp
Show template when REGEXP matches the current buffer’s name.
(doct '(("Only in *scratch*" :keys "n" :file "" :contexts (:in-buffer "^\\*scratch\\*$"))))
:unless-buffer regexp
Show template unless REGEXP matches the current buffer’s name.
(doct '(("Except in *scratch*" :keys "n" :file "" :contexts (:unless-buffer "^\\*scratch\\*$"))))
:in-file regexp
Show template when REGEXP matches the current buffer’s file name.
(doct '(("Only in work.org" :keys "n" :file "" :contexts (:in-file "work\\.org$"))))
:unless-file regexp
Show template unless REGEXP matches the current buffer’s file name.
(doct '(("Except in work.org" :keys "n" :file "" :contexts (:unless-file "work\\.org$"))))
:in-mode regexp
Show template when REGEXP matches the current buffer’s major mode.
(doct '(("Only in org-mode" :keys "n" :file "" :contexts (:in-mode "org-mode"))))
:unless-mode regexp
Show template unless REGEXP matches the current buffer’s major mode.
(doct '(("Except in org-mode" :keys "n" :file "" :contexts (:unless-mode "org-mode"))))
:when condition
Show template when CONDITION evaluates to a non-nil value. Condition may be a function or a single form.
(doct '(("Show when my/predicate-p returns t" :keys "n" :file "" :contexts (:when my/predicate-p))))
(doct '(("1/3 chance of showing" :keys "n" :file "" :contexts (:when (= 2 (random 3))))))
:unless condition
Show template when CONDITION evaluates to a nil value. Condition may be a function or a single form.
(doct '(("Show when my/predicate-p returns nil" :keys "n" :file "" :contexts (:unless my/predicate-p))))
(doct '(("2/3 chance of showing" :keys "n" :file "" :contexts (:unless (= 2 (random 3))))))
:function function
Show template when FUNCTION returns non-nil. The function is not passed any arguments.
(doct '(("Between 9AM and 5PM" :keys "n" :file ""
         :contexts (:function (lambda () (<= 9 (string-to-number (format-time-string "%H")) 17)))))))

Adding :keys to a rule does the same as above, but remaps the template’s keys to the template with keys matching the :keys string. For example:

(doct '(("In *scratch* remapped to t, else use original template"
         :keys "n" :file "" :contexts ((:unless-buffer "^\\*scratch\\*$" :keys "n")
                                       (:in-buffer     "^\\*scratch\\*$" :keys "t")))))

The above rule keywords, spare :function, :when, and :unless may also take a list of strings for their values.

(doct '(("Only in org-mode or emacs-lisp-mode" :keys "n" :file ""
         :contexts (:in-mode ("org-mode" "emacs-lisp-mode")))))

Disabling Templates

Setting the :disabled keyword to t disables a template. The template’s declaration is not error checked. This can be useful if you don’t have the time to deal with an error right away. For example:
(doct '((:group "All" :file "" :children
                ((:group "Enabled" :children
                         (("One"   :keys "1")
                          ("Two"   :keys "2")
                          ("Three" :keys "3")))
                 (:group "Disabled" :disabled t :children
                         (("Four" :keys 4)
                          ("Five" :keys 5)
                          ("Six"  :keys 6)))))))

returns:

(("1" "One"   entry (file "") nil)
 ("2" "Two"   entry (file "") nil)
 ("3" "Three" entry (file "") nil))

Normally template “Four” would throw an error because its :keys are not a string.

Disabling Warnings

The :warn keyword disables doct’s warnings on a per-declaration basis. For example:

(let ((doct-warnings t))
  (doct '(("Ignore unbound symbol warnings" :keys "i"
           :warn (:not unbound)
           :file     unbound-variable
           :function unbound-function)
          ("Warn here, though" :keys "w"
           :file     unbound-variable
           :function unbound-function))))

For global control of warnings and an explanation of accepted values see doct-warnings in Custom Variables.

doct-add-to

(doct-add-to list declarations &optional append)

Return a copy of LIST with converted DECLARATIONS added. If APPEND is non-nil, add to back of LIST. Otherwise, add to the front of LIST. DECLARATIONS are passed to doct and must be the same of the same form doct accepts.

e.g.

;; `org-capture-templates' set earlier elsewhere...

(setq org-capture-templates
      (doct-add-to org-capture-templates
                   '("example" :keys "e" ...)
                   'append))

Custom Variables

doct supports the following variables for customization:
doct-default-entry-type ‘entry
The default template entry type. It can be overridden on a per-declaration basis by using the :type keyword.
doct-after-conversion-functions
Abnormal hook run after converting declarations to templates. Hook functions run with the list of templates as their only argument. The templates are not flattened at this point and are of the form:
(((parent) (child)...)...).
    
doct-warnings
When non-nil, doct will issue warnings. Valid values are:
t
warn in all cases
nil
do not warn

Or a list containing any of the following symbols:

unbound
warn when a symbol is unbound during conversion
template-keyword
warn when %{KEYWORD} is not found on the declaration during conversion.
template-keyword-type
warn when %{KEYWORD} expansion does not return a string.
template-entry-type
warn when the expanded template string does not match the capture template’s entry type
template-file
warn when the :template-file’s file is not found during conversion
option-type
warn when additional options are not the proper type

If the list’s first element is the :not keyword, the list of warnings is disabled. It can be overridden on a per-declaration basis with the :warn keyword.”

For example:

(let ((doct-warnings t))
  (doct '(("Ignore unbound symbol warnings" :keys "i"
           :warn (:not unbound)
           :file     unbound-variable
           :function unbound-function)
          ("Warn here, though" :keys "w"
           :file     unbound-variable
           :function unbound-function))))
    

Contributing

Pull/feature requests, code review, angry comments are all welcome.

Please add a test to the test suite if you introduce any changes.

Thanks, nv

doct's People

Contributors

progfolio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

doct's Issues

unbound variable in doct--target-file

Hello! Thanks for making doct, looks like it is going to make my capture templates a lot easier to read and maintain.

I've run into a problem that I seem unable to solve by careful reading of the README. Maybe you could just point out where I need to read more carefully?

I am struggling with datetrees. Based on reading the docs, I expected the following config:

      (doct '(
	      (:group "mygtd.org entries"
	       :type entry
	       :file "~/Dropbox/org/mygtd.org"
	       :children
	       ((...))
	      ("Journal Entries"
	       :type entry
	       :keys "j"
	       :file "~/Dropbox/org/journal.org"
	       :datetree t
	       :children
	       (("General Journal Entry"
		 :keys "j"
		 :template "* %? \nENTERED: %U  \n\n  ")
		("Retrospective"
		 :keys "r"
		 :template-file "~/Dropbox/org/templates/retro_journal_entry.org")
		))
	      )))

to produce something along these lines:

	(...)
	("j" "Journal Entries")
	("jj" "General Journal Entry" entry (file+datetree "~/Dropbox/org/journal.org")
	 "* %? \nENTERED: %U  \n\n  ")
	("jr" "Retrospective" entry (file+datetree "~/Dropbox/org/journal.org")
	 (file "~/Dropbox/org/templates/retro_journal_entry.org"))
	(...)

Instead, I get a debugger buffer starting with the below. Everything else seems to work fine, and this is the first time I'm trying to use :datetree. Am I doing it wrong?

Debugger entered--Lisp error: (void-variable datetree)
  #f(compiled-function (type target path) #<bytecode 0x15773f61b045>)((nil) (nil) nil)
  doct--target-file("~/Dropbox/org/journal.org")
  doct--target()
  doct--compose-entry("jj" "General Journal Entry" nil)
  doct--convert("General Journal Entry" :keys "j" :datetree "t" :template "* %? \nENTERED: %U  \n\n  " :type entry :inherited-keys "jj" :file "~/Dropbox/org/journal.org")
  apply(doct--convert ("General Journal Entry" :keys "j" :datetree "t" :template "* %? \nENTERED: %U  \n\n  " :type entry :inherited-keys "jj" :file "~/Dropbox/org/journal.org"))

%{keyword} expansion fails for :template-file

Describe the problem

I've been trying to track down why a template file I have wasn't expanding the %{doct-keyword} like it seemed it should, based on the description of the functionality.

I moved the template into the :template call itself and the expansion happened as advertised, but if my template lives in a file, and is expanded through :template-file, the %{doct-keyword} fields all show up as %{doct-keyword}

I haven't been able to find anything in the documentation that says what I'm hoping to accomplish shouldn't work (and it's easily possible that my limited elisp is to blame)

Directions to reproduce

Create the template file (/tmp/org-test/templates/task-) with the content:

* %{todo-state} %^{Description}
%^{timetype|DEADLINE:|SCHEDULED:} %^t
:PROPERTIES:
:ID: %^{ID|%(car (process-lines "uuidgen"))}
:CREATED: %U
:LASTUPDATED: %U
:SPECIAL: %{other-key}
:SOURCE: %{source-template}
:END:
%?

Evaluate the following (probably relies on having set up org-capture and doct, for me the setq is inside the :config portion of my (use-package doct) call)

(defvar my/org-dir
  "/tmp/org-test")

(defvar my/org-template-dir
  (expand-file-name "templates" my/org-dir))

(defvar my/org-capture-inbox-file
  (expand-file-name "inbox.org" my/org-dir))

(setq org-capture-templates
      (doct `(("Tasks" :keys "t" :headline "Tasks"
               :prepend t
               :empty-lines 1
               :immediate-finish t
               :source-template "in-place"
               :file my/org-capture-inbox-file
               :template ("* %{todo-state} %^{Description}"
                          "%^{timetype|DEADLINE:|SCHEDULED:} %^t"
                          ":PROPERTIES:"
                          ":ID: %^{ID|%(car (process-lines \"uuidgen\"))}"
                          ":CREATED: %U"
                          ":LASTUPDATED: %U"
                          ":SPECIAL: %{other-key}"
                          ":SOURCE: %{source-template}"
                          ":END:"
                          "%?")
               :children (("To-do"     :keys "t" :todo-state "TODO"  :other-key "this will work")
                          ("Next"      :keys "n" :todo-state "NEXT"  :other-key "this will work")
                          ("Done"      :keys "d" :todo-state "DONE"  :other-key "this will work")
                          ("Cancelled" :keys "x" :todo-state "CANCELLED"  :other-key "this will work")))
              ("Task template file" :keys "T" :headline "Tasks"
               :prepend t
               :empty-lines 1
               :immediate-finish t
               :file js/org-capture-inbox-file
               :source-template "file"
               :template-file ,(expand-file-name "task-template.org" my/org-template-dir)
               :children (("To-do"     :keys "t" :todo-state "TODO" :other-key "this will not work")
                          ("Next"      :keys "n" :todo-state "NEXT" :other-key "this will not work")
                          ("Done"      :keys "d" :todo-state "DONE" :other-key "this will not work")
                          ("Cancelled" :keys "x" :todo-state "CANCELLED" :other-key "this will not work"))))))

Capturing with C-c c t t results in:

** TODO Doct template inline
   DEADLINE: <2020-09-06 Sun>
   :PROPERTIES:
   :ID:       b4b9a8a1-25c0-4731-af71-cb18e3f89f4f
   :CREATED:  [2020-09-06 Sun 18:46]
   :LASTUPDATED: [2020-09-06 Sun 18:46]
   :SPECIAL:  this will work
   :SOURCE:   in-place
   :END:

Capturing with C-c c T t (using the template file) results in:

** %{todo-state} Doct template from file
   DEADLINE: <2020-09-06 Sun>
   :PROPERTIES:
   :ID:       6e8ab07a-a273-47e8-b41a-6aff99b86f16
   :CREATED:  [2020-09-06 Sun 18:46]
   :LASTUPDATED: [2020-09-06 Sun 18:46]
   :SPECIAL:  %{other-key}
   :SOURCE:   %{source-template}
   :END:

Note that the three %{doct-keyword} placeholders are not picking up their keyword values from the config.

Apologies if this is a result of my incorrect application of doct or elisp, but I thought that since I was able to seemingly isolate it to whether the template comes from :template or from :template-file, it would be worth it to create an issue.
Thanks for your work in putting together this very useful package!

Version information

  • Emacs version:
GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.22, cairo version 1.17.3) of 2020-08-28
  • Org mode version:
Org mode version 9.3.7 (release_9.3.7-705-gea9463 @ mixed installation! /usr/share/emacs/27.1/lisp/org/ and /home/${USER}/.config/emacs/straight/build/org/)
  • Operating system: Arch linux, kernel version 5.8.5-arch1-1

how about to set tag?

Some distro like Debian or GNU Guix prefer to add to their repository only "completed" software, where authors set tag in order to say "our software is ready to stable use". How about to set tag someday?

How to use "doct-add-to"?

I would like to add a doct template, to my existing list of templates. I get errors, could it be possible to have a little help? This is my code:

(setopt org-capture-templates
(doct-add-to org-capture-templates
	     `("Proyecto" :keys "y"
	       :type entry
               :id "2023-02-09T12:06:10,23"
               :prepend t
	       :immediate-finish t
	       :jump-to-captured t
	       :hook
               ,(defun +org-capture-captialize-dir-prop ()
                  (save-excursion
                    (goto-char (point-min))
                    (when (re-search-forward "^:DIR:" nil t)
                      (upcase-region (line-beginning-position) (line-end-position)))))	       
	       :template ("* PROY %^{CLIENTE} _%^{OT}_ /%^{Descripción}/
:PROPERTIES:
:DIR: z:/! 2023/COMERCIAL/OFERTAS/%\\1-%\\2-%\\3
:END:
** Gestión del Proyecto
*** Contacto
*** Datos de partida
*** Reunión %\\1
*** SIG. Ofertar
*** T-AD Facturar")
	       'append)))

Error message:


condition-case: DOCT Wrong type argument: (doct--plist-p), (properties (:keys "y" :type entry :id "2023-02-09T12:06:10,23" :prepend t :immediate-finish t :jump-to-captured t :hook +org-capture-captialize-dir-prop :template ("* PROY %^{CLIENTE} _%^{OT}_ /%^{Descripción}/
:PROPERTIES:
:DIR: z:/! 2023/COMERCIAL/OFERTAS/%\\1-%\\2-%\\3
:END:
** Gestión del Proyecto
*** Contacto
*** Datos de partida
*** Reunión %\\1
*** SIG. Ofertar
*** T-AD Facturar") 'append)), ("Proyecto" :keys "y" :type entry :id "2023-02-09T12:06:10,23" :prepend t :immediate-finish t :jump-to-captured t :hook +org-capture-captialize-dir-prop :template ("* PROY %^{CLIENTE} _%^{OT}_ /%^{Descripción}/
:PROPERTIES:
:DIR: z:/! 2023/COMERCIAL/OFERTAS/%\\1-%\\2-%\\3
:END:
** Gestión del Proyecto
*** Contacto
*** Datos de partida
*** Reunión %\\1
*** SIG. Ofertar
*** T-AD Facturar") 'append)

org-roam integration

Very new to emacs (doom) and am using org-roam plus doct.

# desired filename output
20200520231937-storage.org

# generated successfully without doct with
:file-name "%(format-time-string \"%Y-%m-%d--%H-%M-%SZ--${slug}\" (current-time) t)"

I've attempted a few ways to achieve the desired effect however I must be missing something

 (use-package! org-roam
  :hook
  (after-init . org-roam-mode)
  :config
  (setq org-roam-capture-templates
        (doct '(("New SSH Episode" :keys "e"
                     :file "~/Nextcloud/org/personal/ssh/"
                     ;:file (lambda() (concat (format-time-string "%Y-%m-%d--%H-%M-%SZ--${slug}") (current-time) ".org"))
                     ;:file-name "~/Nextcloud/org/personal/ssh/"
                     ;:file-name "~/Nextcloud/org/personal/ssh/%(format-time-string \"%Y-%m-%d--%H-%M-%SZ--${slug}\" (current-time) t)"
                     :function org-roam--capture-get-point
                     :type plain
                     :template "#+ROAM_ALIAS: \"SSH Episode %^{PROMPT|Episode Number (short)?|}\"
#+AIRDATE: %^{PROMPT|Air Date? (yyyy-mm-dd)|2020-|}
#+EPISODE_URL: https://selfhosted.show/%\\1
#+EPISODE_TITLE: %^{PROMPT|Episode Title?|}

* Fireside Episode Description: %?")))))

All of the above options return a filename that looks like this

20200525235930.org

As per the first code block I would love the "slug" to be in the actual filename rather than just an ambiguous date. So I must be missing something really simple and would really appreciate some assistance here. Thanks!

Documentation update to explain `:datetree` needs `:olp` not `:headline`

I'm trying to set up my Org config so I'm using doct -- so far, it's pretty awesome!

However, I got stuck trying to move my file+olp+datetree capture targets to doct.

I thought that this would work:

(setq org-capture-templates
      (doct
       '(("Top Level Date-Tree Test 1"
          :keys "m" 
          :file "~/date-tree-test.org"
          :headline "Meetings"
          :datetree t
          :template "* SCHEDULED %^{Meeting Title} \n%?"
          :jump-to-captured t)
         ("Child Date-Tree Tests"
          :keys "p"
          :children (("Child Test 1"
                      :keys "m" 
                      :file "~/date-tree-test.org" 
                      :type entry
                      :headline "Meetings"
                      :datetree t
                      :template "* SCHEDULED %^{Meeting Title} \n%?"
                      :jump-to-captured t))
          ))))

But it wasn't working and I couldn't figure out why. It kept creating a date-tree at the bottom of the file as a new top-level heading instead of putting the date-tree under the headline I specified.

I didn't find out that to specify a heading with :datetree you need to use :olp ("Heading") instead of :headline "Heading" until I found this on Reddit. Is that how it's supposed to work, or is that a bug?

If that's how it's supposed to work then I can do a PR to update the README so it's clear, but I wanted to check first.

Parent's :custom plist overrides children properties

Part of my org-capture-template config is as follows:

    ("Project" :keys "p"
                   :icon ("repo" :set "octicon" :color "silver")
                   :prepend t
                   :type entry
                   :headline "Inbox"
                   :template ("* %{time-or-todo} %?"
                              "%i"
                              "%a")
                   :custom (:time-or-todo "")
                   :children (("Project-local todo" :keys "t"
                               :icon ("checklist" :set "octicon" :color "green")
                               :time-or-todo "TODO"
                               :function +org-capture-project-todo-file)
                              ("Project-local note" :keys "n"
                               :icon ("sticky-note" :set "faicon" :color "yellow")
                               :time-or-todo "%U"
                               :file +org-capture-project-notes-file)
                              ("Project-local changelog" :keys "c"
                               :icon ("list" :set "faicon" :color "blue")
                               :time-or-todo "%U"
                               :heading "Unreleased"
                               :file +org-capture-project-changelog-file))

This code is not using the specified templates.
when I used "Project-local todo" it gives me this template:
3
when I used "Project-local changelog" it gives me this template:
1
when I used "Project-local note" it gives me this template:
2

How to capitalize the text entered from other prompt?

Hi

I have been referred to this doct package, from de orgmode mail list.

I have read the documentation, but still I don't know how to achieve what I am trying: (I am not a programmer).

Could it be possible, in org-capture, to capitalize the text entered from a previous prompt?

Example:
I have this part of an org-capture template:

* %^{CLIENT} _%^{Project}_ /%^{Description}/
:PROPERTIES:
:DIR: z:/! 2023/%\\1-%\\2-%\\3
:END:

I would like to know if it could be possible to “capitalize” the used data that I entered before. For example, instead of this:

** Client _Project Number_ /Project description/
:PROPERTIES:
:DIR: z:/! 2023/Client-Project Number-Project description
:END:

I want to get this: (The 3rd line is “capitalized”)

** Client _Project Number_ /Project description/
:PROPERTIES:
:DIR: z:/! 2023/CLIENT-PROJECT NUMBER-PROJECT DESCRIPTION
:END:

Best regards

issues with some completion packages?

using templates that contain the new "%doct()" construct causes an error to be thrown with the following functions.

Debugger entered--Lisp error: (wrong-type-argument symbolp (lambda nil (string-join (mapcar (function doct--fill-deferred-template) ("* %doct(todo-state) %?" "  %a")) "\n")))
  fboundp((lambda nil (string-join (mapcar (function doct--fill-deferred-template) ("* %doct(todo-state) %?" "  %a")) "\n")))
  org-capture-get-template()
  org-capture(nil "t")
  (closure (org-attach-directory org-indent-indentation-per-level org-indent-mode counsel-yank-pop-truncate-radius smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (org-capture nil (car (split-string x))))("t     Todo")
  ivy-call()
  ivy-read("Capture template: " ("p     [.emacs.d] Task" "t     Todo" "T     Todo with Clipboard" "h     Homework") :require-match t :action (closure (org-attach-directory org-indent-indentation-per-level org-indent-mode counsel-yank-pop-truncate-radius smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (org-capture nil (car (split-string x)))) :caller counsel-org-capture)
  counsel-org-capture()
  counsel-projectile-org-capture()
  funcall-interactively(counsel-projectile-org-capture)
  call-interactively(counsel-projectile-org-capture record nil)
  command-execute(counsel-projectile-org-capture record)
  counsel-M-x-action("counsel-projectile-org-capture")
  ivy-call()
  ivy-read("M-x " ("org-capture" "org-id-copy" "mohkale/find-capture-notes-file" "evil-version" "eshell" "haskell-repl" "describe-key" "keycast-mode" "haskell-indent-mode" "evil-multiedit" "flyspell-mode" "flyspell-correct-wrapper" "vertical-display-last-buffer" "counsel-evil-marks" "count-words" "hydra-flyspell/body" "which-key-mode" "kill-region" "prettify-symbols-mode" "server-start" "powerline-reset" "haskell-indentation-mode" "sort-lines" "pp-macroexpand-last-sexp" "ialign" "dired-omit-mode" "evil-snipe-mode" "display-last-buffer" "olivetti-mode" "python-repl" "counsel-package" "org-insert-item" "byte-compile-file" "package-refresh-contents" "rake" "ruby-mode" "package-install" "visual-line-mode" "copy-region-as-kill" "hl-highlight-thingatpt-local" "ivy-find-file-new-perspective" "lsp" "widen" "ansi-term" "html-mode" "fringe-mode" "show-prefix" "check-parens" "font-lock-mode" "hydra-visual-move/body" ...) :predicate (closure ((externs "org-capture" "org-id-copy" "mohkale/find-capture-notes-file" "evil-version" "eshell" "haskell-repl" "describe-key" "keycast-mode" "haskell-indent-mode" "evil-multiedit" "flyspell-mode" "flyspell-correct-wrapper" "vertical-display-last-buffer" "counsel-evil-marks" "count-words" "hydra-flyspell/body" "which-key-mode" "kill-region" "prettify-symbols-mode" "server-start" "powerline-reset" "haskell-indentation-mode" "sort-lines" "pp-macroexpand-last-sexp" "ialign" "dired-omit-mode" "evil-snipe-mode" "display-last-buffer" "olivetti-mode" "python-repl" "counsel-package" "org-insert-item" "byte-compile-file" "package-refresh-contents" "rake" "ruby-mode" "package-install" "visual-line-mode" "copy-region-as-kill" "hl-highlight-thingatpt-local" "ivy-find-file-new-perspective" "lsp" "widen" "ansi-term" "html-mode" "fringe-mode" "show-prefix" "check-parens" "font-lock-mode" ...) (initial-input) smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (not (get (intern x) (quote no-counsel-M-x)))) :require-match t :history counsel-M-x-history :action counsel-M-x-action :keymap (keymap (100663342 . counsel-find-symbol) (67108908 . counsel--info-lookup-symbol) (67108910 . hydra-ivy/body)) :initial-input nil :caller counsel-M-x)
  (let ((externs (counsel--M-x-externs))) (ivy-read (counsel--M-x-prompt) (or externs obarray) :predicate (if externs (function (lambda (x) (not (get (intern x) (quote no-counsel-M-x))))) (function (lambda (sym) (and (commandp sym) (not (get sym ...)) (not (get sym ...)))))) :require-match t :history (quote counsel-M-x-history) :action (function counsel-M-x-action) :keymap counsel-describe-map :initial-input initial-input :caller (quote counsel-M-x)))
  counsel-M-x()
  funcall-interactively(counsel-M-x)
  call-interactively(counsel-M-x nil nil)
  command-execute(counsel-M-x)
Debugger entered--Lisp error: (wrong-type-argument symbolp (lambda nil (string-join (mapcar (function doct--fill-deferred-template) ("* %doct(todo-state) %?" "  %a")) "\n")))
  fboundp((lambda nil (string-join (mapcar (function doct--fill-deferred-template) ("* %doct(todo-state) %?" "  %a")) "\n")))
  org-capture-get-template()
  org-capture(nil "t")
  (closure (org-attach-directory org-indent-indentation-per-level org-indent-mode counsel-yank-pop-truncate-radius smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (org-capture nil (car (split-string x))))("t     Todo")
  ivy-call()
  ivy-read("Capture template: " ("t     Todo" "T     Todo with Clipboard" "h     Homework") :require-match t :action (closure (org-attach-directory org-indent-indentation-per-level org-indent-mode counsel-yank-pop-truncate-radius smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (org-capture nil (car (split-string x)))) :caller counsel-org-capture)
  counsel-org-capture()
  funcall-interactively(counsel-org-capture)
  call-interactively(counsel-org-capture record nil)
  command-execute(counsel-org-capture record)
  counsel-M-x-action("counsel-org-capture")
  ivy-call()
  ivy-read("M-x " ("counsel-org-capture" "counsel-projectile-org-capture" "org-capture" "org-id-copy" "mohkale/find-capture-notes-file" "evil-version" "eshell" "haskell-repl" "describe-key" "keycast-mode" "haskell-indent-mode" "evil-multiedit" "flyspell-mode" "flyspell-correct-wrapper" "vertical-display-last-buffer" "counsel-evil-marks" "count-words" "hydra-flyspell/body" "which-key-mode" "kill-region" "prettify-symbols-mode" "server-start" "powerline-reset" "haskell-indentation-mode" "sort-lines" "pp-macroexpand-last-sexp" "ialign" "dired-omit-mode" "evil-snipe-mode" "display-last-buffer" "olivetti-mode" "python-repl" "counsel-package" "org-insert-item" "byte-compile-file" "package-refresh-contents" "rake" "ruby-mode" "package-install" "visual-line-mode" "copy-region-as-kill" "hl-highlight-thingatpt-local" "ivy-find-file-new-perspective" "lsp" "widen" "ansi-term" "html-mode" "fringe-mode" "show-prefix" "check-parens" ...) :predicate (closure ((externs "counsel-org-capture" "counsel-projectile-org-capture" "org-capture" "org-id-copy" "mohkale/find-capture-notes-file" "evil-version" "eshell" "haskell-repl" "describe-key" "keycast-mode" "haskell-indent-mode" "evil-multiedit" "flyspell-mode" "flyspell-correct-wrapper" "vertical-display-last-buffer" "counsel-evil-marks" "count-words" "hydra-flyspell/body" "which-key-mode" "kill-region" "prettify-symbols-mode" "server-start" "powerline-reset" "haskell-indentation-mode" "sort-lines" "pp-macroexpand-last-sexp" "ialign" "dired-omit-mode" "evil-snipe-mode" "display-last-buffer" "olivetti-mode" "python-repl" "counsel-package" "org-insert-item" "byte-compile-file" "package-refresh-contents" "rake" "ruby-mode" "package-install" "visual-line-mode" "copy-region-as-kill" "hl-highlight-thingatpt-local" "ivy-find-file-new-perspective" "lsp" "widen" "ansi-term" "html-mode" "fringe-mode" "show-prefix" ...) (initial-input) smex-ido-cache smex-initialized-p amx-cache amx-initialized info-lookup-mode t) (x) (not (get (intern x) (quote no-counsel-M-x)))) :require-match t :history counsel-M-x-history :action counsel-M-x-action :keymap (keymap (100663342 . counsel-find-symbol) (67108908 . counsel--info-lookup-symbol) (67108910 . hydra-ivy/body)) :initial-input nil :caller counsel-M-x)
  (let ((externs (counsel--M-x-externs))) (ivy-read (counsel--M-x-prompt) (or externs obarray) :predicate (if externs (function (lambda (x) (not (get (intern x) (quote no-counsel-M-x))))) (function (lambda (sym) (and (commandp sym) (not (get sym ...)) (not (get sym ...)))))) :require-match t :history (quote counsel-M-x-history) :action (function counsel-M-x-action) :keymap counsel-describe-map :initial-input initial-input :caller (quote counsel-M-x)))
  counsel-M-x()
  funcall-interactively(counsel-M-x)
  call-interactively(counsel-M-x nil nil)
  command-execute(counsel-M-x)

I am lossing the underscore

Describe the problem

When I use _ before the ‘%\N’ (the text entered at the Nth ‘%^{PROMPT}’) the _ dissapears.

Directions to reproduce

(setopt org-capture-templates
  (doct-add-to org-capture-templates
               `("Project" :keys "j"
                 :type entry
                 :id "2024"
                 :prepend t
                 :immediate-finish t
                 :jump-to-captured t
                 :hook
                 ,(defun +org-capture-captialize-dir-prop ()
                    (save-excursion
                      (goto-char (point-min))
                      (when (re-search-forward "^:DIR:" nil t)
                        (upcase-region (line-beginning-position) (line-end-position)))))
                 :template ("* PROJ %^{1 CLIENT}-_%^{2 OT}_
$Contract_%\\2 := 10000 EUR$))))

Instead of "Contract_2 OT" it writes down "Contract2 OT", the _ is missing.

Version information

  • Emacs version: 29.3
  • Org mode version: 9.8-pre
  • Operating system: Win

Dynamic elements in :olp

I split the items I plan and log in my org files based on the year, so the outline paths for my capture templates often look like ("Tasks" "2020" "Habits"). In order to not have to update the templates for every new year I have been trying to dynamically built the olps by including a calls to functions like (format-time-string "%Y").

That doesn't work in doct because it expects the :olp to be a list of strings, so I had to fall back to always providing a full :function.

It'd be great if doct allowed dynamic elements in its :olp, maybe by having (eval (exp)) elements next to strings, or applying the "%(exp)" replacement as in the template.

Note that I am not asking for the dynamic parts to be re-evaluated every time capture is triggered, doing it just once in the doct call is perfectly sufficient for my use-case.

Function output as headline

I am trying to create a weekly journal capture template, but can't figure out the headline part. Basically, I am targeting to get this output:

* Monday, October 17
** 17:07
   captured notes
** 18:45
   other capture

And this is my current setup:

("Journal Capture" :keys "j"
                   :file (lambda () (concat org-journal-dir (format-time-string "%Y-W%W") ".org"))
                   :type entry
                   :date_format (lambda () (format-time-string "%A, %B %d"))
                   :headline "%{date_format}"
                   :template ("** %<%R>"
                                     "%?"))

Set up child-based category

Regards,

Great job with this, it simplifies the templates for org-capture quite a bit.

I have a question or I don't know if it's a feature request.

How can I set the property: CATEGORY: based on a child, I am dealing with this:

(leaf doct
  :straight t
  :leaf-defer nil
  :commands (doct)
  :config
  (setq org-capture-templates
      (doct '(("Work" :keys "w"
               :file "~/org/work.org"
               :prepend t
               :template ("* %doct(todo-state) %^{Description}"
                          "SCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))"
                          ":PROPERTIES:"
                          ":CREATED: %U"
                          ":CATEGORY: %doct(headline)%"
                          ":END:"
                          "%?")
               :children (("Task"  :keys "w"
                           :headline   "Task"
                           :todo-state "TODO"
                           :hook (lambda () (message "\"First Child\" selected.")))
                          ("Second Child" :keys "2"
                           :headline   "Two"
                           :todo-state "NEXT")
                          ("Third Child"  :keys "3"
                           :headline   "Three"
                           :todo-state "MAYBE")))))))

But it doesn't work, you can tell me if this can be done.

PS .: leaf.el the similar to use-package

Thank you

Constant warning regarding doct template

I've defined a few functions for templates like

(defun sr/fun/todo-active ()
'("* %doct(todo-state) %?"
":PROPERTIES:"
":CREATED: %U"
":PLANNED: %t"
":END:"))

which are plugged into templates for capture like

(setq org-capture-templates
      (doct '(("Tasks" :keys "t"
               :file "~/my_org/todo-global.org"
               :prepend t
	       :children (("Fast TODO"  
			   :keys "t"
			   :type entry	                           
			   :headline   "@Inbox"
			   :todo-state "TODO"
			   :template (lambda () (sr/fun/todo-active))))))))

However for each capture, I get the warning

Warning (doct): Old template expansion syntax detected. Upgrading :template value.
Substitute "* %doct(todo-state)" for "* %{todo-state}" in your configuration to prevent this warning in the future.

I have tried replacing %doct(todo-state) with %doct{todo-state} in the function above, as I see some discussion on this breaking change. However then the literal %doct{todo-state} appears in the capture. The warning appears each time I capture. I would be grateful for advice.

Note: I am using the latest commit of doct (9e7cbec) via straight.el

Can I access doct-custom/etc from a :hook function?

I'm using :template "my template", :file myfile.org and :hook (lambda () (my/capture-func)) as well as :my-custom-var1, etc... to enrich the filled template with additional items.

From inside my/capture-func how can I:

  1. access the buffer opened for myfile.org? (Without hardcoding it!)
  2. access the custom custom vars on the doct-custom plist?

declarative yasnippet templates

I just wanted to mention that I really like this idea and I would love to see it
applied to yasnippet templates. I don't like having snippets in a multiple
separate files. And I don't like writing snippets in non lisp. Sometimes I end
up with one snippet that's a huge long line.

Here's an example of what it might look like:

(define-snippet! help-function
  (:mode org-mode)
  (:key "hfn")
  (:body "[[helpfn:$1][%s]]$0")
  (:1 (yas-auto-next (yas-choose-value (void-list-symbols #'functionp)))))

Here's what the macro I wrote to do this looks like:

(defmacro define-snippet! (name &rest properties)
  "Define a yasnippet snippet.
NAME is the description of the snippet."
  (-let* (((&alist :mode :key :body) properties)
          (placeholders (thread-last properties
                          (-filter #'yasnippet--placeholder-p+)
                          (-map #'yasnippet--to-placeholder+))))
    `(after! yasnippet
       (with-temp-buffer
         (insert ,(apply #'format
                         (s-join "\n" (-snoc yasnippet-template+ body))
                         (append (list 'snippet-mode name key)
                                 placeholders)))
         (yas-load-snippet-buffer ',mode)))))

It uses the dash libraries and some helper functions/macros I wrote. I might end
up writing a package for this I'm not sure yet. I just wanted to ask you if this
is something that seems interesting to you.

Org 9.5 capture refile-targets

With the release of org 9.5 there is an option to define refile targets when exiting capture mode with org-capture-refile. It takes the same format as org-refile-targets and uses the :refile-targets property in the capture template. I was able to get it to work adding the property to doct-option-keywords. I just wanted to bring to your attention.

warnings issued with example doct.

Describe the problem

In the README, there's an example doct:

(doct '(("Parent" :keys "p"
         :file "~/example.org"
         :prepend t
         :template ("* %doct(todo-state) %^{Description}"
                    ":PROPERTIES:"
                    ":Created: %U"
                    ":END:"
                    "%?")
         :children (("First Child"  :keys "1"
                     :headline   "One"
                     :todo-state "TODO"
                     :hook (lambda () (message "\"First Child\" selected.")))
                    ("Second Child" :keys "2"
                     :headline   "Two"
                     :todo-state "NEXT")
                    ("Third Child"  :keys "3"
                     :headline   "Three"
                     :todo-state "MAYBE")))))

If I try to evaluate it I get a tonne of warnings.

Directions to reproduce

  1. Copy the example doct to your *scratch* buffer.
  2. evaluate your scratch buffer (using eval-buffer).

When I do so, the warnings buffer pops up with the following messages.

Warning (doct): :template %?
:END:
:Created: %U
:PROPERTIES:
* TODO %^{Description} in declaration:
(First Child :keys p1 :headline One :todo-state TODO :hook (lambda nil (message "First Child" selected.)) :file ~/example.org :prepend t :template (* %doct(todo-state) %^{Description} :PROPERTIES: :Created: %U :END: %?))
is not a valid Org entry
Are you missing the leading ’*’?
Warning (doct): :template %?
:END:
:Created: %U
:PROPERTIES:
* NEXT %^{Description} in declaration:
(Second Child :keys p2 :headline Two :todo-state NEXT :file ~/example.org :prepend t :template (* %doct(todo-state) %^{Description} :PROPERTIES: :Created: %U :END: %?))
is not a valid Org entry
Are you missing the leading ’*’?
Warning (doct): :template %?
:END:
:Created: %U
:PROPERTIES:
* MAYBE %^{Description} in declaration:
(Third Child :keys p3 :headline Three :todo-state MAYBE :file ~/example.org :prepend t :template (* %doct(todo-state) %^{Description} :PROPERTIES: :Created: %U :END: %?))
is not a valid Org entry
Are you missing the leading ’*’?

Version information

  • Emacs version: GNU Emacs 27.0.60 (build 1, x86_64-w64-mingw32) of 2019-12-28
  • Org mode version: Org mode version 9.3.6 (9.3.6-elpa @ c:/Users/MoHKale/.emacs.d/bin/elpa/org-9.3.6/)
  • Operating system: Windows 10

Doct with org-journal

Hi,
First of all thank you for the good work done on DOCT.

Context

I tried to adapt the capture provided by org-journal with DOCT but it does not work.

(defun org-journal-find-location ()
  ;; Open today's journal, but specify a non-nil prefix argument in order to
  ;; inhibit inserting the heading; org-capture will insert the heading.
  (org-journal-new-entry t)
  (unless (eq org-journal-file-type 'daily)
    (org-narrow-to-subtree))
  (goto-char (point-max)))

(setq org-capture-templates '(("j" "Journal entry" plain (function org-journal-find-location)
                               "** %(format-time-string org-journal-time-format)%^{Title}\n%i%?"
                               :jump-to-captured t :immediate-finish t)))

Errors

  • When I leave the 2 ** in the template it shows me an error
Warning (doct): expanded :template "** %(format-time-string org-journal-time-format)%^{Title}
%i%?" in the "Journal" declaration is not a valid Org entry.
  Are you missing the leading ’*’?
  • When I leave a single * it does not indent the hourly headline
* mercredi, 13/07/2022
:PROPERTIES:
:CREATED:  20220713
:END:
* 10:11 essai
test

Template

("Journal" :keys "j"
	:icon ("book" :set "octicon" :color "orange")
	:function ,(defun org-journal-find-location ()
				;; Open today's journal, but specify a non-nil prefix argument in order to
				;; inhibit inserting the heading; org-capture will insert the heading.
				(org-journal-new-entry t)
				(unless (eq org-journal-file-type 'yearly)
					(org-narrow-to-subtree))
				(goto-char (point-max)))
	:template ("** %(format-time-string org-journal-time-format)%^{Title}"
			"%i%?"))

Does the problem come from my adaptation or is this a bug ?

Getting DOCT to declare the entries for org-roam

I'm trying to use DOCT, but I can't figure out how to configure the two entries for org-roam.

I'm not really an expert, so I find the documentation kind of complicated.

med venlig hilsen (=With Kind Regards)
Niels

Method to combine doct with org-roam templates?

I am a happy user of doct, and a recent user of org-roam. I'm unable to figure out the method of using the org-roam function with the doct capture templates. I would appreciate advice on this.

So I have multiple templates defined in functions like

(defun sr/fun/todo-act-date ()
'("* %{todo-state} %?"
":PROPERTIES:"
":CREATED: %<%Y-%m-%d %a %H:%M>"
":PLANNED: %^t"
":END:"))

And then org-capture templates are defined something like:

(setq org-capture-templates
      (doct '(
              ("Todo" :keys "t"
               :file "~/my_org/roam/00_private/todo-global.org"
               :prepend t
               :children (("inbox"
                           :keys "t"
                           :type entry
                           :headline "@inbox"
                           :todo-state "TODO"
                           :template sr/fun/todo-act-date)))

I have tried using the template keyword to use the org-roam-capture function, but this resulted in a syntax error.

Org-roam's manual (https://org-roam.readthedocs.io/en/master/templating/) mentions that it leverages org-capture under the hood.

Please let me know if you require any further information.

How to reference the template description string?

I find myself creating a lot of templates similar to these:

(let ((org-capture-templates
       (doct '("Call" :keys "c"
               :type entry
               :file "/tmp/test.org"
               :template "* %{desc} %{comm-type}: %?"
               :children
                (("Tech Support" :keys "t" :desc "Tech Support" :comm-type "Call")
                 ("Billing"      :keys "b" :desc "Billing"      :comm-type "Call")
                 ("Admin"        :keys "a" :desc "Admin"        :comm-type "Call")
                 )))))
  (org-capture nil "ct"))

The redundancy of having the :desc and :comm-type properties being the same as the template title/descriptions bothers me, but I haven't been able to figure out how to refer to the description of my template, let alone the description of the parent group. Is something like this possible? At least the child ones if not the parent?

flatten-list

I'm not sure when it got introduced, but the latest HEAD includes a call to flatten-list which is not defined in Emacs 26.

:clock-in on root heading

Hello,

Thanks for this package - I think it is a nice idea for developing capture templates. I have successfully set up a template which I want to use :clock-in t. This works fine, however, if I also use %? to assert where the cursor should be after the template is created, the clock will be assigned to that (sub)headline.

Is there any way to ensure that the clock is assigned to the highest headline within the template? As a work around, I am removing the %?.

`:olp` path dropped when `:datetree` declared first

Describe the problem

When trying to use :datetree, :olp, and :time-prompt to capture meetings that occur in the future the date tree doesn't get created in the right location. Rather than position the date tree as a subheading under the heading defined by :olp, it places the date tree as a top-level heading at the bottom of the file.

With a minimal configuration file (below), this is what shows up in the customize menu for Org Capture:

18-02-2022 14:41:32

If you look carefully, you can see Outline path checkbox is un-ticked, despite having :olp ("Meetings") in the configuration.

Directions to reproduce

I've put a sample configuration file, as well as an example Org file and the template file in this gist.

When doing two captures for a date in the future, this is what gets put into my Org file:

* First Heading
* Meetings
* Test Heading

* 2022

** 2022-02 February

*** 2022-02-21 Monday
**** TODO First Test

boop

*** 2022-02-22 Tuesday
**** TODO Second Test

another test

It's not using the :olp ("Meetings") bit to position the start of the date tree as a second-level heading. It also doesn't seem to be respecting the :empty-lines 0 argument, either.

I'm not sure if this is a doct thing or an org thing, but I figured I'd see if it was an issue with doct ( or, you know, my config ) before moving further upstream and submitting a bug to org.

Version information

  • Emacs version: GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.31, cairo version 1.17.4) of 2022-02-17 ( compiled from git://git.sv.gnu.org/emacs.git, on the master branch with commit 246f627a4125d8b3ae5e88748a439f3f594340b5, with --with-native-compilation --with-xwidgets as the flags passed to ./configure )
  • Org mode version: Org mode version 9.5.2 (9.5.2-g37d8bc @ /home/sean/.emacs.d/packages/straight/build/org/)
  • Doct version: development branch, commit ce21bce19b91e6f1dfc1f23983b4b8ce4464c8f5
  • Operating system: Manjaro Linux 21.2.3

Add syntax for adding property drawers to the templates

It would be handy if I could do something like

(doct '("Example"
	:keys "t"
        :file yant/org-inbox-file
	:template
	("* TODO sample task"
	 :properties (("CREATED" . "%U")
	              ":STYLE: habit"
		          ("REPEAT_TO_STATE" . "NEXT")
		          ("LOGGING" . "DONE(!)")
		          ("ARCHIVE" . "%%S_archive_%%y:*Habits")
		          ("ORG-TIME-BONUS-ON-DONE" . "60"))
	 "%?")))

org-roam / DOCT

Hello,
Here I am again,
Using the snippets (without changes), I get this messages (and the graphic i roam don't work)

Warning (doct): :function org-roam-capture--get-point unbound during conversion in the "default" declaration
Warning (doct): :function org-roam-capture--get-point unbound during conversion in the "ref" declaration

Here is the actual code:

(setq org-roam-capture-templates
(doct-org-roam '(("default"
:keys "d"
:type plain
:function org-roam-capture--get-point
:template "%?"
:org-roam ( :file-name "%<%Y%m%d%H%M%S>-${slug}"
:head "#+TITLE: ${title}\n"
:unnarrowed t))
("ref"
:keys "r"
:type plain
:function org-roam-capture--get-point
:template ""
:org-roam ( :file-name "${slug}"
:head "#+TITLE: ${title}\n"
:unnarrowed t)))))
mvh
Niels

Change %doct(keyword) syntax

@floscr @LemonBreezes @fuzzycode @contrun @BumbleBeeBleep @mohkale @arkhan @swflint @ndw

I'm considering introducing a breaking change to doct and I was curious if anyone has any opinions or ideas about it.
Recently @jethrokuan and I discussed the possibility of org-roam using doct.
The template string replacement syntax in org-roam is %{keyword} vs doct's %doct(keyword).
I'm considering switching to %{keyword} in doct, too.

  • Pros
    Less to type.
    Non-breaking compatibility w org-roam. Easier integration. Has potential to bring more use/users to doct.
    Makes use of doct more transparent to other packages that wish to require it.

  • Unsure
    Close in syntax to org-capture's vanilla %^{prompt} syntax.
    I could see arguments in favor and against this.

  • Cons
    This would be a breaking change for current doct users.

I'll leave this issue open for a week or so before making a decision.
As always, I appreciate all of you helping to make doct a better package.

Thanks,
Nick Vollmer.

Refactor "symbolic-parent" to :group

"Group" is the concept we want. The fact that it's implemented with symbols is irrelevant. The group keyword should also take a string as its value to describe the group:

(:group "My Group" :foo t ;etc
            :children (("Example" ;...
)))

%{KEYWORD} Expansion fails when KEYWORD is a function modifying match-data

Describe the problem

When using %{KEYWORD} expansion with KEYWORD set to (lambda () ... (re-search-forward ...))), capturing fails silently.
I tracked this down to doct--replace-template-strings where the following code assumes that match data is not modified by the user function.

(replace-match (if (functionp val)
                                 (doct--replace-template-strings (funcall val))
                               (or val ""))
                             nil t))

I think that the funcall must be wrapped into save-match-data to avoid replace-match throwing error.

Version information

  • Emacs version: master
  • Org mode version: master
  • Operating system: Linux

Doct modifies list argument

Hello,

I am trying to put some common children under different parents as shown below. But this does not work. Both ct and it put the todo item under the currently clocked item. After running the code the value of my/basic-capture-types is changed to this:

(("Todo" :keys "t" :template "* TODO %?" :inherited-keys "it" :clock t :file "inbox.org") ("Entry" :keys "e" :template "* TODO %?
%a" :inherited-keys "ie" :clock t :file "inbox.org"))

Is this meant to happen? If yes, what would be an other way to accomplish this?
Thank You!

;; These are the type of capture-templates
(setq my/basic-capture-types
      ;; Simple todo entry
      '(("Todo" :keys "t"
         :template "* TODO %?")
        ;; Link to current entry
        ("Entry" :keys "e"
         :template "* TODO %?\n%a")))

;; Here I will add the capture types to different locations
(setq org-capture-templates
      (doct
       `(("Clock" :keys "c" :clock t
          :children ,my/basic-capture-types)
         ("Inbox" :keys "i" :file "inbox.org"
          :children ,my/basic-capture-types))))

Unable to use doct with `add-to-list`

Hello; Thanks for implementing this macro (It's been fairly useful)

My current Emacs workflow involves me defining and adding capture templates from multiple files, and as such I would like to be able to to use add-to-list instead of setq:

(add-to-list 'org-capture-templates
      (doct `(("Note"
               :keys "n"
               :file ,my-notes-file
               :type entry
               :template ("* %^{DESCRIPTION} %^g"
                          ":PROPERTIES:"
                          ":CREATED: %U"
                          ":END:"
                          "%?")))))

However doct seems to return a list of lists, which (as far as I can tell) makes it unable to integrate with existing org-capture-template entries.

Passing doct a single list generates a Wrong type argument: listp error, and I'm not sure if manually extracting it from the list would break something.

I would like to be able to incrementally call doct and add capture templates as needed, instead of having to define it all in a single call. Is that possible?

Add (require 'seq)

Declarative templates are a nice addition to Org. I hope that they get folded into the main release. In the meantime, I was experimenting and discovered that seq-filter is used so (require 'seq) is necessary.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.