问题
I want to generate strings containing Org-mode text without actually hard-coding the syntax. For example i want to run a function such as (org-generate (org-generate-heading "heading" (org-generate-plain-list '("foo" "bar" "baz")))
and it will return:
* heading
- foo
- bar
- baz
In other words, i want to create Org-mode documents of arbitrary complexity without micromanaging syntactic features like asterisks and indentation, only via calling functions with parameters, that return some Org objects. Is it possible to do that? Maybe via org-element
?
回答1:
INITIAL (March 14, 2014): First rough draft.
EDIT (March 15, 2014): Created and revised the function named example
. The path of the let-bound variable org-file
must coincide with an existing org-mode file. The let-bound variables main-heading
and sub-heading
are not being used at this time due to an apparent limitation with using variables in a list that begins with '(
-- i.e., those two variables are not recognized under this circumstance. The function org-capture
from org-capture.el
has been modified to include the contents of the function org-capture-set-plist
, which in turn has been modified to eliminate the first two elements of org-capture-entry
(aka org-capture-templates
) -- both entries (i.e., :key
and :description
) are for manually selecting a template from the user-interface, and are not needed when generating an org buffer programmatically as is being done with this example
. In addition, the portions of the function org-capture
relating to manually selecting a template have been removed.
EDIT (March 16, 2014): Revised variables and list handling based upon lessons provided by @sds and @lunaryorn in the following thread: https://stackoverflow.com/a/22440518/2112489 Added four optional incoming variables -- (1) main-heading
; (2) sub-heading-headline
; (3) sub-heading-complete
; and (4) plain-list
. The example now work either interactively, or by evaluating the function using the following format: (org-generate "PROJECT" "Thesis" "** Thesis\n:PROPERTIES:\n:END:" '("a" "b" "c"))
EDIT (March 19, 2014): org-generate
is now a non-interactive function that requires incoming variables -- the doc-string has been updated. Created a function named example
that utilizes the new format for org-generate
.
;; EXAMPLES:
;; (org-generate 'entry "/Users/HOME/Desktop/myproject.org" "PROJECT" "Thesis" "** Thesis\n :PROPERTIES:\n :END:")
;; (org-generate 'item "/Users/HOME/Desktop/myproject.org" "PROJECT" "Thesis" nil '("a" "b" "c"))
(defun example ()
(interactive)
(let* (
(org-file "/Users/HOME/Desktop/myproject.org")
(level-one "TASKS")
(level-two
"Active [\#A] Generate Org-mode objects programmatically.")
(full-level-two (concat
"** Active [\#A] Generate Org-mode objects programmatically.\n"
" DEADLINE: <%<%Y-%m-%d %a>>\n"
" :PROPERTIES:\n"
" :ToodledoFolder: TASKS\n"
" :END:"))
(plain-list '("foo" "bar" "baz")) )
(org-generate 'entry org-file level-one level-two full-level-two)
(org-generate 'item org-file level-one level-two nil plain-list) ))
(defun org-generate (type org-file level-one
&optional level-two full-level-two plain-list)
"Formating options for `org-capture-entry` are similar to `org-capture-templates`.
However, the first two elements (i.e., `:key` and `:description`) are NOT used.
Please see the doc-string of the variable `org-capture-templates` for more info.
(1) `type`: required -- 'entry | 'item
(2) `org-file`: required -- path to the org-mode file.
(3) `level-one`: required -- main heading.
(4) `level-two`: optional -- sub-heading headline (only).
(5) `full-level-two`: optional -- complete sub-heading.
(6) `plain-list`: optional -- a list.
EXAMPLES:
`(org-generate 'entry org-file level-one level-two full-level-two)`
`(org-generate 'item org-file level-one level-two nil plain-list)` "
(require 'org-capture)
(let (org-capture-entry)
(cond
((eq type 'entry)
(setq org-capture-entry
`(entry
(file+headline ,org-file ,level-one)
,full-level-two :empty-lines 1 :immediate-finish t))
(lawlist-org-capture))
((eq type 'item)
(setq org-capture-entry
`(item
(file+olp ,org-file ,level-one ,level-two)
nil :empty-lines 1 :immediate-finish t))
(mapcar (lambda (x)
(progn
(setcar (nthcdr 2 org-capture-entry) x)
(lawlist-org-capture) ))
plain-list)))))
(defun lawlist-org-capture ()
(let* ((orig-buf (current-buffer))
(annotation (if (and (boundp 'org-capture-link-is-already-stored)
org-capture-link-is-already-stored)
(plist-get org-store-link-plist :annotation)
(ignore-errors (org-store-link nil))))
(entry org-capture-entry)
initial)
(setq initial (or org-capture-initial
(and (org-region-active-p)
(buffer-substring (point) (mark)))))
(when (stringp initial)
(remove-text-properties 0 (length initial) '(read-only t) initial))
(when (stringp annotation)
(remove-text-properties 0 (length annotation)
'(read-only t) annotation))
(setq org-capture-plist (copy-sequence (nthcdr 3 entry)))
(org-capture-put :target (nth 1 entry))
(let ((txt (nth 2 entry)) (type (or (nth 0 entry) 'entry)))
(when (or (not txt) (and (stringp txt) (not (string-match "\\S-" txt))))
(cond
((eq type 'item) (setq txt "- %?"))
((eq type 'checkitem) (setq txt "- [ ] %?"))
((eq type 'table-line) (setq txt "| %? |"))
((member type '(nil entry)) (setq txt "* %?\n %a"))))
(org-capture-put :template txt :type type))
(org-capture-get-template)
(org-capture-put :original-buffer orig-buf
:original-file (or (buffer-file-name orig-buf)
(and (featurep 'dired)
(car (rassq orig-buf
dired-buffers))))
:original-file-nondirectory
(and (buffer-file-name orig-buf)
(file-name-nondirectory
(buffer-file-name orig-buf)))
:annotation annotation
:initial initial
:return-to-wconf (current-window-configuration)
:default-time
(or org-overriding-default-time
(org-current-time)))
(org-capture-set-target-location)
(condition-case error
(org-capture-put :template (org-capture-fill-template))
((error quit)
(if (get-buffer "*Capture*") (kill-buffer "*Capture*"))
(error "Capture abort: %s" error)))
(setq org-capture-clock-keep (org-capture-get :clock-keep))
(condition-case error
(org-capture-place-template
(equal (car (org-capture-get :target)) 'function))
((error quit)
(if (and (buffer-base-buffer (current-buffer))
(string-match "\\`CAPTURE-" (buffer-name)))
(kill-buffer (current-buffer)))
(set-window-configuration (org-capture-get :return-to-wconf))
(error "Error.")))
(if (and (derived-mode-p 'org-mode)
(org-capture-get :clock-in))
(condition-case nil
(progn
(if (org-clock-is-active)
(org-capture-put :interrupted-clock
(copy-marker org-clock-marker)))
(org-clock-in)
(org-set-local 'org-capture-clock-was-started t))
(error
"Could not start the clock in this capture buffer")))
(if (org-capture-get :immediate-finish)
(org-capture-finalize))))
(source: lawlist.com)
来源:https://stackoverflow.com/questions/22411626/generate-org-mode-objects-programmatically