summaryrefslogtreecommitdiff
path: root/lisp/org-capture.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org-capture.el')
-rw-r--r--lisp/org-capture.el199
1 files changed, 167 insertions, 32 deletions
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index 9d20814..a4f0fd0 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -1,6 +1,6 @@
;;; org-capture.el --- Fast note taking in Org-mode
-;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2010-2013 Free Software Foundation, Inc.
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -50,7 +50,6 @@
(eval-when-compile
(require 'cl))
(require 'org)
-(require 'org-mks)
(declare-function org-datetree-find-date-create "org-datetree"
(date &optional keep-restriction))
@@ -182,6 +181,8 @@ properties are:
template only needs information that can be added
automatically.
+ :jump-to-captured When set, jump to the captured entry when finished.
+
:empty-lines Set this to the number of lines the should be inserted
before and after the new item. Default 0, only common
other value is 1.
@@ -223,7 +224,9 @@ freely formatted text. Furthermore, the following %-escapes will
be replaced with content and expanded in this order:
%[pathname] Insert the contents of the file given by `pathname'.
- %(sexp) Evaluate elisp `(sexp)' and replace with the result.
+ %(sexp) Evaluate elisp `(sexp)' and replace it with the results.
+ For convenience, %:keyword (see below) placeholders within
+ the expression will be expanded prior to this.
%<...> The result of format-time-string on the ... format specification.
%t Time stamp, date only.
%T Time stamp with date and time.
@@ -237,7 +240,7 @@ be replaced with content and expanded in this order:
%x Content of the X clipboard.
%k Title of currently clocked task.
%K Link to currently clocked task.
- %n User name (taken from `user-full-name').
+ %n User name (taken from the variable `user-full-name').
%f File visited by current buffer when org-capture was called.
%F Full path of the file or directory visited by current buffer.
%:keyword Specific information for certain link types, see below.
@@ -338,11 +341,15 @@ calendar | %:type %:date"
;; Give the most common options as checkboxes
:options (((const :format "%v " :prepend) (const t))
((const :format "%v " :immediate-finish) (const t))
+ ((const :format "%v " :jump-to-captured) (const t))
((const :format "%v " :empty-lines) (const 1))
+ ((const :format "%v " :empty-lines-before) (const 1))
+ ((const :format "%v " :empty-lines-after) (const 1))
((const :format "%v " :clock-in) (const t))
((const :format "%v " :clock-keep) (const t))
((const :format "%v " :clock-resume) (const t))
((const :format "%v " :unnarrowed) (const t))
+ ((const :format "%v " :table-line-pos) (const t))
((const :format "%v " :kill-buffer) (const t))))))))
(defcustom org-capture-before-finalize-hook nil
@@ -434,10 +441,12 @@ Turning on this mode runs the normal hook `org-capture-mode-hook'."
;;; The main commands
-;;;###autoload
(defvar org-capture-initial nil)
(defvar org-capture-entry nil)
+
+;;;###autoload
(defun org-capture-string (string &optional keys)
+ "Capture STRING with the template selected by KEYS."
(interactive "sInitial text: \n")
(let ((org-capture-initial string)
(org-capture-entry (org-capture-select-template keys)))
@@ -450,7 +459,7 @@ For example, if you have a capture template \"c\" and you want
this template to be accessible only from `message-mode' buffers,
use this:
- '((\"c\" (in-mode . \"message-mode\")))
+ '((\"c\" ((in-mode . \"message-mode\"))))
Here are the available contexts definitions:
@@ -458,6 +467,8 @@ Here are the available contexts definitions:
in-mode: command displayed only in matching modes
not-in-file: command not displayed in matching files
not-in-mode: command not displayed in matching modes
+ in-buffer: command displayed only in matching buffers
+not-in-buffer: command not displayed in matching buffers
[function]: a custom function taking no argument
If you define several checks, the agenda command will be
@@ -466,11 +477,11 @@ accessible if there is at least one valid check.
You can also bind a key to another agenda custom command
depending on contextual rules.
- '((\"c\" \"d\" (in-mode . \"message-mode\")))
+ '((\"c\" \"d\" ((in-mode . \"message-mode\"))))
-Here it means: in `message-mode buffers', use \"d\" as the
+Here it means: in `message-mode buffers', use \"c\" as the
key for the capture template otherwise associated with \"d\".
-\(The template originally associated with \"q\" is not displayed
+\(The template originally associated with \"d\" is not displayed
to avoid duplicates.)"
:version "24.3"
:group 'org-capture
@@ -483,6 +494,8 @@ to avoid duplicates.)"
(choice
(const :tag "In file" in-file)
(const :tag "Not in file" not-in-file)
+ (const :tag "In buffer" in-buffer)
+ (const :tag "Not in buffer" not-in-buffer)
(const :tag "In mode" in-mode)
(const :tag "Not in mode" not-in-mode))
(regexp))
@@ -490,7 +503,7 @@ to avoid duplicates.)"
(defcustom org-capture-use-agenda-date nil
"Non-nil means use the date at point when capturing from agendas.
-When nil, you can still capturing using the date at point with \\[org-agenda-capture]]."
+When nil, you can still capture using the date at point with \\[org-agenda-capture]."
:group 'org-capture
:version "24.3"
:type 'boolean)
@@ -513,17 +526,19 @@ stored.
When called with a `C-0' (zero) prefix, insert a template at point.
-Lisp programs can set KEYS to a string associated with a template
+ELisp programs can set KEYS to a string associated with a template
in `org-capture-templates'. In this case, interactive selection
will be bypassed.
If `org-capture-use-agenda-date' is non-nil, capturing from the
-agenda will use the date at point as the default date."
+agenda will use the date at point as the default date. Then, a
+`C-1' prefix will tell the capture process to use the HH:MM time
+of the day at point (if any) or the current HH:MM time."
(interactive "P")
(when (and org-capture-use-agenda-date
(eq major-mode 'org-agenda-mode))
(setq org-overriding-default-time
- (org-get-cursor-date)))
+ (org-get-cursor-date (equal goto 1))))
(cond
((equal goto '(4)) (org-capture-goto-target))
((equal goto '(16)) (org-capture-goto-last-stored))
@@ -599,7 +614,7 @@ agenda will use the date at point as the default date."
(error
"Could not start the clock in this capture buffer")))
(if (org-capture-get :immediate-finish)
- (org-capture-finalize nil)))))))))
+ (org-capture-finalize)))))))))
(defun org-capture-get-template ()
"Get the template from a file or a function if necessary."
@@ -624,6 +639,8 @@ agenda will use the date at point as the default date."
With prefix argument STAY-WITH-CAPTURE, jump to the location of the
captured item after finalizing."
(interactive "P")
+ (when (org-capture-get :jump-to-captured)
+ (setq stay-with-capture t))
(unless (and org-capture-mode
(buffer-base-buffer (current-buffer)))
(error "This does not seem to be a capture buffer for Org-mode"))
@@ -892,7 +909,8 @@ Store them in the capture property list."
(current-time))))
(org-capture-put
:default-time
- (cond ((and (not org-time-was-given)
+ (cond ((and (or (not (boundp 'org-time-was-given))
+ (not org-time-was-given))
(not (= (time-to-days prompt-time) (org-today))))
;; Use 00:00 when no time is given for another date than today?
(apply 'encode-time (append '(0 0 0) (cdddr (decode-time prompt-time)))))
@@ -963,7 +981,7 @@ it. When it is a variable, retrieve the value. Return whatever we get."
(find-file-noselect (expand-file-name file org-directory)))))
(defun org-capture-steal-local-variables (buffer)
- "Install Org-mode local variables."
+ "Install Org-mode local variables of BUFFER."
(mapc (lambda (v)
(ignore-errors (org-set-local (car v) (cdr v))))
(buffer-local-variables buffer)))
@@ -978,7 +996,7 @@ it. When it is a variable, retrieve the value. Return whatever we get."
(show-all)
(goto-char (org-capture-get :pos))
(org-set-local 'org-capture-target-marker
- (move-marker (make-marker) (point)))
+ (point-marker))
(org-set-local 'outline-level 'org-outline-level)
(let* ((template (org-capture-get :template))
(type (org-capture-get :type)))
@@ -1249,7 +1267,8 @@ Of course, if exact position has been required, just put it there."
(save-restriction
(widen)
(goto-char pos)
- (bookmark-set "org-capture-last-stored")
+ (with-demoted-errors
+ (bookmark-set "org-capture-last-stored"))
(move-marker org-capture-last-stored-marker (point)))))))
(defun org-capture-narrow (beg end)
@@ -1259,7 +1278,7 @@ Of course, if exact position has been required, just put it there."
(goto-char beg)))
(defun org-capture-empty-lines-before (&optional n)
- "Arrange for the correct number of empty lines before the insertion point.
+ "Set the correct number of empty lines before the insertion point.
Point will be after the empty lines, so insertion can directly be done."
(setq n (or n (org-capture-get :empty-lines-before)
(org-capture-get :empty-lines) 0))
@@ -1269,7 +1288,7 @@ Point will be after the empty lines, so insertion can directly be done."
(if (> n 0) (newline n))))
(defun org-capture-empty-lines-after (&optional n)
- "Arrange for the correct number of empty lines after the inserted string.
+ "Set the correct number of empty lines after the inserted string.
Point will remain at the first line after the inserted text."
(setq n (or n (org-capture-get :empty-lines-after)
(org-capture-get :empty-lines) 0))
@@ -1280,8 +1299,9 @@ Point will remain at the first line after the inserted text."
(goto-char pos)))
(defvar org-clock-marker) ; Defined in org.el
-;;;###autoload
+
(defun org-capture-insert-template-here ()
+ "Insert the capture template at point."
(let* ((template (org-capture-get :template))
(type (org-capture-get :type))
beg end pp)
@@ -1364,8 +1384,106 @@ Use PREFIX as a prefix for the name of the indirect buffer."
(unless (org-kill-is-subtree-p tree)
(error "Template is not a valid Org entry or tree")))
-;;; The template code
+(defun org-mks (table title &optional prompt specials)
+ "Select a member of an alist with multiple keys.
+TABLE is the alist which should contain entries where the car is a string.
+There should be two types of entries.
+
+1. prefix descriptions like (\"a\" \"Description\")
+ This indicates that `a' is a prefix key for multi-letter selection, and
+ that there are entries following with keys like \"ab\", \"ax\"...
+
+2. Selectable members must have more than two elements, with the first
+ being the string of keys that lead to selecting it, and the second a
+ short description string of the item.
+
+The command will then make a temporary buffer listing all entries
+that can be selected with a single key, and all the single key
+prefixes. When you press the key for a single-letter entry, it is selected.
+When you press a prefix key, the commands (and maybe further prefixes)
+under this key will be shown and offered for selection.
+
+TITLE will be placed over the selection in the temporary buffer,
+PROMPT will be used when prompting for a key. SPECIAL is an alist with
+also (\"key\" \"description\") entries. When one of these is selection,
+only the bare key is returned."
+ (setq prompt (or prompt "Select: "))
+ (let (tbl orig-table dkey ddesc des-keys allowed-keys
+ current prefix rtn re pressed buffer (inhibit-quit t))
+ (save-window-excursion
+ (setq buffer (org-switch-to-buffer-other-window "*Org Select*"))
+ (setq orig-table table)
+ (catch 'exit
+ (while t
+ (erase-buffer)
+ (insert title "\n\n")
+ (setq tbl table
+ des-keys nil
+ allowed-keys nil
+ cursor-type nil)
+ (setq prefix (if current (concat current " ") ""))
+ (while tbl
+ (cond
+ ((and (= 2 (length (car tbl))) (= (length (caar tbl)) 1))
+ ;; This is a description on this level
+ (setq dkey (caar tbl) ddesc (cadar tbl))
+ (pop tbl)
+ (push dkey des-keys)
+ (push dkey allowed-keys)
+ (insert prefix "[" dkey "]" "..." " " ddesc "..." "\n")
+ ;; Skip keys which are below this prefix
+ (setq re (concat "\\`" (regexp-quote dkey)))
+ (let (case-fold-search)
+ (while (and tbl (string-match re (caar tbl))) (pop tbl))))
+ ((= 2 (length (car tbl)))
+ ;; Not yet a usable description, skip it
+ )
+ (t
+ ;; usable entry on this level
+ (insert prefix "[" (caar tbl) "]" " " (nth 1 (car tbl)) "\n")
+ (push (caar tbl) allowed-keys)
+ (pop tbl))))
+ (when specials
+ (insert "-------------------------------------------------------------------------------\n")
+ (let ((sp specials))
+ (while sp
+ (insert (format "[%s] %s\n"
+ (caar sp) (nth 1 (car sp))))
+ (push (caar sp) allowed-keys)
+ (pop sp))))
+ (push "\C-g" allowed-keys)
+ (goto-char (point-min))
+ (if (not (pos-visible-in-window-p (point-max)))
+ (org-fit-window-to-buffer))
+ (message prompt)
+ (setq pressed (char-to-string (read-char-exclusive)))
+ (while (not (member pressed allowed-keys))
+ (message "Invalid key `%s'" pressed) (sit-for 1)
+ (message prompt)
+ (setq pressed (char-to-string (read-char-exclusive))))
+ (when (equal pressed "\C-g")
+ (kill-buffer buffer)
+ (error "Abort"))
+ (when (and (not (assoc pressed table))
+ (not (member pressed des-keys))
+ (assoc pressed specials))
+ (throw 'exit (setq rtn pressed)))
+ (unless (member pressed des-keys)
+ (throw 'exit (setq rtn (rassoc (cdr (assoc pressed table))
+ orig-table))))
+ (setq current (concat current pressed))
+ (setq table (mapcar
+ (lambda (x)
+ (if (and (> (length (car x)) 1)
+ (equal (substring (car x) 0 1) pressed))
+ (cons (substring (car x) 1) (cdr x))
+ nil))
+ table))
+ (setq table (remove nil table)))))
+ (when buffer (kill-buffer buffer))
+ rtn))
+;;; The template code
(defun org-capture-select-template (&optional keys)
"Select a capture template.
Lisp programs can force the template by setting KEYS to a string."
@@ -1494,10 +1612,8 @@ The template may still contain \"%?\" for cursor positioning."
(setq v-i (mapconcat 'identity
(org-split-string initial "\n")
(concat "\n" lead))))))
- (replace-match
- (or (org-add-props (eval (intern (concat "v-" (match-string 1))))
- '(org-protected t)) "")
- t t)))
+ (replace-match (or (eval (intern (concat "v-" (match-string 1)))) "")
+ t t)))
;; From the property list
(when plist-p
@@ -1513,8 +1629,7 @@ The template may still contain \"%?\" for cursor positioning."
(let ((org-inhibit-startup t)) (org-mode))
;; Interactive template entries
(goto-char (point-min))
- (while (and (re-search-forward "%^\\({\\([^}]*\\)}\\)?\\([gGtTuUCLp]\\)?" nil t)
- (not (get-text-property (1- (point)) 'org-protected)))
+ (while (re-search-forward "%^\\({\\([^}]*\\)}\\)?\\([gGtTuUCLp]\\)?" nil t)
(unless (org-capture-escaped-%)
(setq char (if (match-end 3) (match-string-no-properties 3))
prompt (if (match-end 2) (match-string-no-properties 2)))
@@ -1619,10 +1734,26 @@ The template may still contain \"%?\" for cursor positioning."
(goto-char (match-beginning 0))
(let ((template-start (point)))
(forward-char 1)
- (let ((result (org-eval (read (current-buffer)))))
+ (let ((result (org-eval
+ (org-capture--expand-keyword-in-embedded-elisp
+ (read (current-buffer))))))
(delete-region template-start (point))
(insert result))))))
+(defun org-capture--expand-keyword-in-embedded-elisp (attr)
+ "Recursively replace capture link keywords in ATTR sexp.
+Such keywords are prefixed with \"%:\". See
+`org-capture-template' for more information."
+ (cond ((consp attr)
+ (mapcar 'org-capture--expand-keyword-in-embedded-elisp attr))
+ ((symbolp attr)
+ (let* ((attr-symbol (symbol-name attr))
+ (key (and (string-match "%\\(:.*\\)" attr-symbol)
+ (intern (match-string 1 attr-symbol)))))
+ (or (plist-get org-store-link-plist key)
+ attr)))
+ (t attr)))
+
(defun org-capture-inside-embedded-elisp-p ()
"Return non-nil if point is inside of embedded elisp %(sexp)."
(let (beg end)
@@ -1641,7 +1772,7 @@ The template may still contain \"%?\" for cursor positioning."
;;;###autoload
(defun org-capture-import-remember-templates ()
- "Set org-capture-templates to be similar to `org-remember-templates'."
+ "Set `org-capture-templates' to be similar to `org-remember-templates'."
(interactive)
(when (and (yes-or-no-p
"Import old remember templates into org-capture-templates? ")
@@ -1658,7 +1789,7 @@ The template may still contain \"%?\" for cursor positioning."
(position (or (nth 4 entry) org-remember-default-headline))
(type 'entry)
(prepend org-reverse-note-order)
- immediate target)
+ immediate target jump-to-captured)
(cond
((member position '(top bottom))
(setq target (list 'file file)
@@ -1672,9 +1803,13 @@ The template may still contain \"%?\" for cursor positioning."
(setq template (replace-match "" t t template)
immediate t))
+ (when (string-match "%&" template)
+ (setq jump-to-captured t))
+
(append (list key desc type target template)
(if prepend '(:prepend t))
- (if immediate '(:immediate-finish t)))))
+ (if immediate '(:immediate-finish t))
+ (if jump-to-captured '(:jump-to-captured t)))))
org-remember-templates))))