Commit | Line | Data |
---|---|---|
20908596 CD |
1 | ;;; org-remember.el --- Fast note taking in Org-mode |
2 | ||
cbd20947 | 3 | ;; Copyright (C) 2004-2011 Free Software Foundation, Inc. |
20908596 CD |
4 | |
5 | ;; Author: Carsten Dominik <carsten at orgmode dot org> | |
6 | ;; Keywords: outlines, hypermedia, calendar, wp | |
7 | ;; Homepage: http://orgmode.org | |
3ab2c837 | 8 | ;; Version: 7.7 |
20908596 CD |
9 | ;; |
10 | ;; This file is part of GNU Emacs. | |
11 | ;; | |
b1fc2b50 | 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
20908596 | 13 | ;; it under the terms of the GNU General Public License as published by |
b1fc2b50 GM |
14 | ;; the Free Software Foundation, either version 3 of the License, or |
15 | ;; (at your option) any later version. | |
20908596 CD |
16 | |
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
b1fc2b50 | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
20908596 CD |
24 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
25 | ;; | |
26 | ;;; Commentary: | |
27 | ||
28 | ;; This file contains the system to take fast notes with Org-mode. | |
33306645 | 29 | ;; This system is used together with John Wiegley's `remember.el'. |
20908596 CD |
30 | |
31 | ;;; Code: | |
32 | ||
33 | (eval-when-compile | |
34 | (require 'cl)) | |
35 | (require 'org) | |
3ab2c837 | 36 | (require 'org-compat) |
8bfe682a | 37 | (require 'org-datetree) |
20908596 | 38 | |
621f83e4 | 39 | (declare-function remember-mode "remember" ()) |
20908596 CD |
40 | (declare-function remember "remember" (&optional initial)) |
41 | (declare-function remember-buffer-desc "remember" ()) | |
42 | (declare-function remember-finalize "remember" ()) | |
3ab2c837 | 43 | |
20908596 | 44 | (defvar remember-save-after-remembering) |
20908596 CD |
45 | (defvar remember-register) |
46 | (defvar remember-buffer) | |
47 | (defvar remember-handler-functions) | |
48 | (defvar remember-annotation-functions) | |
621f83e4 CD |
49 | (defvar org-clock-heading) |
50 | (defvar org-clock-heading-for-remember) | |
20908596 CD |
51 | |
52 | (defgroup org-remember nil | |
53 | "Options concerning interaction with remember.el." | |
54 | :tag "Org Remember" | |
55 | :group 'org) | |
56 | ||
57 | (defcustom org-remember-store-without-prompt t | |
86fbb8ca CD |
58 | "Non-nil means \\<org-remember-mode-map>\\[org-remember-finalize] \ |
59 | stores the remember note without further prompts. | |
b349f79f | 60 | It then uses the file and headline specified by the template or (if the |
ce4fdcb9 | 61 | template does not specify them) by the variables `org-default-notes-file' |
ff4be292 | 62 | and `org-remember-default-headline'. To force prompting anyway, use |
86fbb8ca | 63 | \\[universal-argument] \\[org-remember-finalize] to file the note. |
b349f79f | 64 | |
86fbb8ca | 65 | When this variable is nil, \\[org-remember-finalize] gives you the prompts, and |
c5e87d10 | 66 | \\[universal-argument] \\[org-remember-finalize] triggers the fast track." |
20908596 CD |
67 | :group 'org-remember |
68 | :type 'boolean) | |
69 | ||
70 | (defcustom org-remember-interactive-interface 'refile | |
71 | "The interface to be used for interactive filing of remember notes. | |
72 | This is only used when the interactive mode for selecting a filing | |
73 | location is used (see the variable `org-remember-store-without-prompt'). | |
33306645 | 74 | Allowed values are: |
20908596 CD |
75 | outline The interface shows an outline of the relevant file |
76 | and the correct heading is found by moving through | |
77 | the outline or by searching with incremental search. | |
78 | outline-path-completion Headlines in the current buffer are offered via | |
79 | completion. | |
80 | refile Use the refile interface, and offer headlines, | |
81 | possibly from different buffers." | |
82 | :group 'org-remember | |
83 | :type '(choice | |
84 | (const :tag "Refile" refile) | |
85 | (const :tag "Outline" outline) | |
86 | (const :tag "Outline-path-completion" outline-path-completion))) | |
87 | ||
88 | (defcustom org-remember-default-headline "" | |
89 | "The headline that should be the default location in the notes file. | |
90 | When filing remember notes, the cursor will start at that position. | |
91 | You can set this on a per-template basis with the variable | |
92 | `org-remember-templates'." | |
93 | :group 'org-remember | |
94 | :type 'string) | |
95 | ||
96 | (defcustom org-remember-templates nil | |
97 | "Templates for the creation of remember buffers. | |
98 | When nil, just let remember make the buffer. | |
86fbb8ca CD |
99 | When non-nil, this is a list of (up to) 6-element lists. In each entry, |
100 | the first element is the name of the template, which should be a single | |
101 | short word. The second element is a character, a unique key to select | |
102 | this template. The third element is the template. | |
20908596 CD |
103 | |
104 | The fourth element is optional and can specify a destination file for | |
105 | remember items created with this template. The default file is given | |
106 | by `org-default-notes-file'. If the file name is not an absolute path, | |
107 | it will be interpreted relative to `org-directory'. | |
108 | ||
109 | An optional fifth element can specify the headline in that file that should | |
110 | be offered first when the user is asked to file the entry. The default | |
b349f79f CD |
111 | headline is given in the variable `org-remember-default-headline'. When |
112 | this element is `top' or `bottom', the note will be placed as a level-1 | |
113 | entry at the beginning or end of the file, respectively. | |
20908596 | 114 | |
b349f79f CD |
115 | An optional sixth element specifies the contexts in which the template |
116 | will be offered to the user. This element can be a list of major modes | |
117 | or a function, and the template will only be offered if `org-remember' | |
118 | is called from a mode in the list, or if the function returns t. | |
86fbb8ca | 119 | Templates that specify t or nil for the context will always be added |
b349f79f | 120 | to the list of selectable templates. |
20908596 CD |
121 | |
122 | The template specifies the structure of the remember buffer. It should have | |
123 | a first line starting with a star, to act as the org-mode headline. | |
124 | Furthermore, the following %-escapes will be replaced with content: | |
125 | ||
86fbb8ca CD |
126 | %^{PROMPT} prompt the user for a string and replace this sequence with it. |
127 | A default value and a completion table can be specified like this: | |
20908596 | 128 | %^{prompt|default|completion2|completion3|...} |
86fbb8ca CD |
129 | The arrow keys access a prompt-specific history. |
130 | %a annotation, normally the link created with `org-store-link' | |
131 | %A like %a, but prompt for the description part | |
132 | %i initial content, copied from the active region. If %i is | |
133 | indented, the entire inserted text will be indented as well. | |
20908596 CD |
134 | %t time stamp, date only |
135 | %T time stamp with date and time | |
136 | %u, %U like the above, but inactive time stamps | |
b349f79f | 137 | %^t like %t, but prompt for date. Similarly %^T, %^u, %^U. |
86fbb8ca | 138 | You may define a prompt like %^{Please specify birthday}t |
20908596 | 139 | %n user name (taken from `user-full-name') |
b349f79f CD |
140 | %c current kill ring head |
141 | %x content of the X clipboard | |
20908596 | 142 | %:keyword specific information for certain link types, see below |
86fbb8ca CD |
143 | %^C interactive selection of which kill or clip to use |
144 | %^L like %^C, but insert as link | |
145 | %k title of the currently clocked task | |
146 | %K link to the currently clocked task | |
147 | %^g prompt for tags, completing tags in the target file | |
148 | %^G prompt for tags, completing all tags in all agenda files | |
149 | %^{PROP}p Prompt the user for a value for property PROP | |
150 | %[PATHNAME] insert the contents of the file given by PATHNAME | |
151 | %(SEXP) evaluate elisp `(SEXP)' and replace with the result | |
152 | %! store this note immediately after completing the template\ | |
153 | \\<org-remember-mode-map> | |
154 | (skipping the \\[org-remember-finalize] that normally triggers storing) | |
155 | %& jump to target location immediately after storing note | |
156 | %? after completing the template, position cursor here. | |
20908596 CD |
157 | |
158 | Apart from these general escapes, you can access information specific to the | |
159 | link type that is created. For example, calling `remember' in emails or gnus | |
160 | will record the author and the subject of the message, which you can access | |
afe98dfa | 161 | with %:fromname and %:subject, respectively. Here is a complete list of what |
20908596 CD |
162 | is recorded for each link type. |
163 | ||
164 | Link type | Available information | |
165 | -------------------+------------------------------------------------------ | |
166 | bbdb | %:type %:name %:company | |
167 | vm, wl, mh, rmail | %:type %:subject %:message-id | |
168 | | %:from %:fromname %:fromaddress | |
169 | | %:to %:toname %:toaddress | |
170 | | %:fromto (either \"to NAME\" or \"from NAME\") | |
afe98dfa CD |
171 | gnus | %:group, for messages also all email fields and |
172 | | %:org-date (the Date: header in Org format) | |
20908596 CD |
173 | w3, w3m | %:type %:url |
174 | info | %:type %:file %:node | |
175 | calendar | %:type %:date" | |
176 | :group 'org-remember | |
177 | :get (lambda (var) ; Make sure all entries have at least 5 elements | |
178 | (mapcar (lambda (x) | |
179 | (if (not (stringp (car x))) (setq x (cons "" x))) | |
621f83e4 CD |
180 | (cond ((= (length x) 4) (append x '(nil))) |
181 | ((= (length x) 3) (append x '(nil nil))) | |
20908596 CD |
182 | (t x))) |
183 | (default-value var))) | |
184 | :type '(repeat | |
185 | :tag "enabled" | |
186 | (list :value ("" ?a "\n" nil nil nil) | |
187 | (string :tag "Name") | |
188 | (character :tag "Selection Key") | |
189 | (string :tag "Template") | |
b349f79f CD |
190 | (choice :tag "Destination file" |
191 | (file :tag "Specify") | |
621f83e4 | 192 | (function :tag "Function") |
b349f79f CD |
193 | (const :tag "Use `org-default-notes-file'" nil)) |
194 | (choice :tag "Destin. headline" | |
195 | (string :tag "Specify") | |
c8d0cf5c | 196 | (function :tag "Function") |
b349f79f | 197 | (const :tag "Use `org-remember-default-headline'" nil) |
c8d0cf5c | 198 | (const :tag "At beginning of file" top) |
8bfe682a CD |
199 | (const :tag "At end of file" bottom) |
200 | (const :tag "In a date tree" date-tree)) | |
b349f79f CD |
201 | (choice :tag "Context" |
202 | (const :tag "Use in all contexts" nil) | |
20908596 CD |
203 | (const :tag "Use in all contexts" t) |
204 | (repeat :tag "Use only if in major mode" | |
205 | (symbol :tag "Major mode")) | |
206 | (function :tag "Perform a check against function"))))) | |
207 | ||
c8d0cf5c CD |
208 | (defcustom org-remember-delete-empty-lines-at-end t |
209 | "Non-nil means clean up final empty lines in remember buffer." | |
210 | :group 'org-remember | |
211 | :type 'boolean) | |
212 | ||
ce4fdcb9 CD |
213 | (defcustom org-remember-before-finalize-hook nil |
214 | "Hook that is run right before a remember process is finalized. | |
215 | The remember buffer is still current when this hook runs." | |
216 | :group 'org-remember | |
217 | :type 'hook) | |
218 | ||
3ab2c837 | 219 | (defvar org-remember-mode-map (make-sparse-keymap) |
86fbb8ca | 220 | "Keymap for `org-remember-mode', a minor mode. |
ce4fdcb9 CD |
221 | Use this map to set additional keybindings for when Org-mode is used |
222 | for a Remember buffer.") | |
223 | (defvar org-remember-mode-hook nil | |
224 | "Hook for the minor `org-remember-mode'.") | |
225 | ||
226 | (define-minor-mode org-remember-mode | |
227 | "Minor mode for special key bindings in a remember buffer." | |
3ab2c837 BG |
228 | nil " Rem" org-remember-mode-map |
229 | (run-hooks 'org-remember-mode-hook)) | |
230 | (define-key org-remember-mode-map "\C-c\C-c" 'org-remember-finalize) | |
231 | (define-key org-remember-mode-map "\C-c\C-k" 'org-remember-kill) | |
ce4fdcb9 | 232 | |
b349f79f | 233 | (defcustom org-remember-clock-out-on-exit 'query |
ed21c5c8 | 234 | "Non-nil means stop the clock when exiting a clocking remember buffer. |
b349f79f CD |
235 | This only applies if the clock is running in the remember buffer. If the |
236 | clock is not stopped, it continues to run in the storage location. | |
237 | Instead of nil or t, this may also be the symbol `query' to prompt the | |
86fbb8ca | 238 | user each time a remember buffer with a running clock is filed away." |
b349f79f CD |
239 | :group 'org-remember |
240 | :type '(choice | |
241 | (const :tag "Never" nil) | |
242 | (const :tag "Always" t) | |
243 | (const :tag "Query user" query))) | |
244 | ||
c8d0cf5c CD |
245 | (defcustom org-remember-backup-directory nil |
246 | "Directory where to store all remember buffers, for backup purposes. | |
247 | After a remember buffer has been stored successfully, the backup file | |
248 | will be removed. However, if you forget to finish the remember process, | |
249 | the file will remain there. | |
250 | See also `org-remember-auto-remove-backup-files'." | |
251 | :group 'org-remember | |
252 | :type '(choice | |
253 | (const :tag "No backups" nil) | |
254 | (directory :tag "Directory"))) | |
255 | ||
256 | (defcustom org-remember-auto-remove-backup-files t | |
ed21c5c8 | 257 | "Non-nil means remove remember backup files after successfully storage. |
c8d0cf5c CD |
258 | When remember is finished successfully, with storing the note at the |
259 | desired target, remove the backup files related to this remember process | |
260 | and show a message about remaining backup files, from previous, unfinished | |
261 | remember sessions. | |
262 | Backup files will only be made at all, when `org-remember-backup-directory' | |
263 | is set." | |
264 | :group 'org-remember | |
265 | :type 'boolean) | |
b349f79f | 266 | |
54a0dee5 CD |
267 | (defcustom org-remember-warn-about-backups t |
268 | "Non-nil means warn about backup files in `org-remember-backup-directory'. | |
269 | ||
270 | Set this to nil if you find that you don't need the warning. | |
271 | ||
272 | If you cancel remember calls frequently and know when they | |
273 | contain useful information (because you know that you made an | |
86fbb8ca | 274 | error or Emacs crashed, for example) nil is more useful. In the |
54a0dee5 CD |
275 | opposite case, the default, t, is more useful." |
276 | :group 'org-remember | |
277 | :type 'boolean) | |
278 | ||
20908596 CD |
279 | (defvar annotation) ; from remember.el, dynamically scoped in `remember-mode' |
280 | (defvar initial) ; from remember.el, dynamically scoped in `remember-mode' | |
281 | ||
282 | ;;;###autoload | |
283 | (defun org-remember-insinuate () | |
621f83e4 CD |
284 | "Setup remember.el for use with Org-mode." |
285 | (org-require-remember) | |
20908596 CD |
286 | (setq remember-annotation-functions '(org-remember-annotation)) |
287 | (setq remember-handler-functions '(org-remember-handler)) | |
288 | (add-hook 'remember-mode-hook 'org-remember-apply-template)) | |
289 | ||
290 | ;;;###autoload | |
291 | (defun org-remember-annotation () | |
292 | "Return a link to the current location as an annotation for remember.el. | |
293 | If you are using Org-mode files as target for data storage with | |
294 | remember.el, then the annotations should include a link compatible with the | |
295 | conventions in Org-mode. This function returns such a link." | |
296 | (org-store-link nil)) | |
297 | ||
298 | (defconst org-remember-help | |
299 | "Select a destination location for the note. | |
300 | UP/DOWN=headline TAB=cycle visibility [Q]uit RET/<left>/<right>=Store | |
301 | RET on headline -> Store as sublevel entry to current headline | |
302 | RET at beg-of-buf -> Append to file as level 2 headline | |
303 | <left>/<right> -> before/after current headline, same headings level") | |
304 | ||
b349f79f | 305 | (defvar org-jump-to-target-location nil) |
20908596 | 306 | (defvar org-remember-previous-location nil) |
8bfe682a | 307 | (defvar org-remember-reference-date nil) |
20908596 CD |
308 | (defvar org-force-remember-template-char) ;; dynamically scoped |
309 | ||
310 | ;; Save the major mode of the buffer we called remember from | |
311 | (defvar org-select-template-temp-major-mode nil) | |
312 | ||
313 | ;; Temporary store the buffer where remember was called from | |
314 | (defvar org-select-template-original-buffer nil) | |
315 | ||
316 | (defun org-select-remember-template (&optional use-char) | |
317 | (when org-remember-templates | |
318 | (let* ((pre-selected-templates | |
319 | (mapcar | |
320 | (lambda (tpl) | |
321 | (let ((ctxt (nth 5 tpl)) | |
322 | (mode org-select-template-temp-major-mode) | |
323 | (buf org-select-template-original-buffer)) | |
324 | (and (or (not ctxt) (eq ctxt t) | |
325 | (and (listp ctxt) (memq mode ctxt)) | |
326 | (and (functionp ctxt) | |
327 | (with-current-buffer buf | |
328 | ;; Protect the user-defined function from error | |
329 | (condition-case nil (funcall ctxt) (error nil))))) | |
330 | tpl))) | |
331 | org-remember-templates)) | |
332 | ;; If no template at this point, add the default templates: | |
333 | (pre-selected-templates1 | |
334 | (if (not (delq nil pre-selected-templates)) | |
335 | (mapcar (lambda(x) (if (not (nth 5 x)) x)) | |
336 | org-remember-templates) | |
337 | pre-selected-templates)) | |
33306645 | 338 | ;; Then unconditionally add template for any contexts |
20908596 CD |
339 | (pre-selected-templates2 |
340 | (append (mapcar (lambda(x) (if (eq (nth 5 x) t) x)) | |
341 | org-remember-templates) | |
342 | (delq nil pre-selected-templates1))) | |
343 | (templates (mapcar (lambda (x) | |
344 | (if (stringp (car x)) | |
345 | (append (list (nth 1 x) (car x)) (cddr x)) | |
346 | (append (list (car x) "") (cdr x)))) | |
347 | (delq nil pre-selected-templates2))) | |
c8d0cf5c | 348 | msg |
20908596 CD |
349 | (char (or use-char |
350 | (cond | |
351 | ((= (length templates) 1) | |
352 | (caar templates)) | |
353 | ((and (boundp 'org-force-remember-template-char) | |
354 | org-force-remember-template-char) | |
355 | (if (stringp org-force-remember-template-char) | |
356 | (string-to-char org-force-remember-template-char) | |
357 | org-force-remember-template-char)) | |
358 | (t | |
c8d0cf5c | 359 | (setq msg (format |
ed21c5c8 | 360 | "Select template: %s%s" |
c8d0cf5c CD |
361 | (mapconcat |
362 | (lambda (x) | |
363 | (cond | |
364 | ((not (string-match "\\S-" (nth 1 x))) | |
365 | (format "[%c]" (car x))) | |
366 | ((equal (downcase (car x)) | |
367 | (downcase (aref (nth 1 x) 0))) | |
368 | (format "[%c]%s" (car x) | |
369 | (substring (nth 1 x) 1))) | |
370 | (t (format "[%c]%s" (car x) (nth 1 x))))) | |
ed21c5c8 CD |
371 | templates " ") |
372 | (if (assoc ?C templates) | |
373 | "" | |
374 | " [C]customize templates"))) | |
c8d0cf5c CD |
375 | (let ((inhibit-quit t) char0) |
376 | (while (not char0) | |
377 | (message msg) | |
378 | (setq char0 (read-char-exclusive)) | |
379 | (when (and (not (assoc char0 templates)) | |
ed21c5c8 CD |
380 | (not (equal char0 ?\C-g)) |
381 | (not (equal char0 ?C))) | |
c8d0cf5c CD |
382 | (message "No such template \"%c\"" char0) |
383 | (ding) (sit-for 1) | |
384 | (setq char0 nil))) | |
20908596 CD |
385 | (when (equal char0 ?\C-g) |
386 | (jump-to-register remember-register) | |
c8d0cf5c CD |
387 | (kill-buffer remember-buffer) |
388 | (error "Abort")) | |
ed21c5c8 CD |
389 | (when (not (assoc char0 templates)) |
390 | (jump-to-register remember-register) | |
391 | (kill-buffer remember-buffer) | |
392 | (customize-variable 'org-remember-templates) | |
393 | (error "Customize templates")) | |
20908596 CD |
394 | char0)))))) |
395 | (cddr (assoc char templates))))) | |
396 | ||
20908596 CD |
397 | ;;;###autoload |
398 | (defun org-remember-apply-template (&optional use-char skip-interactive) | |
399 | "Initialize *remember* buffer with template, invoke `org-mode'. | |
400 | This function should be placed into `remember-mode-hook' and in fact requires | |
401 | to be run from that hook to function properly." | |
621f83e4 CD |
402 | (when (and (boundp 'initial) (stringp initial)) |
403 | (setq initial (org-no-properties initial)) | |
404 | (remove-text-properties 0 (length initial) '(read-only t) initial)) | |
20908596 CD |
405 | (if org-remember-templates |
406 | (let* ((entry (org-select-remember-template use-char)) | |
b349f79f | 407 | (ct (or org-overriding-default-time (org-current-time))) |
621f83e4 CD |
408 | (dct (decode-time ct)) |
409 | (ct1 | |
410 | (if (< (nth 2 dct) org-extend-today-until) | |
411 | (encode-time 0 59 23 (1- (nth 3 dct)) (nth 4 dct) (nth 5 dct)) | |
412 | ct)) | |
20908596 CD |
413 | (tpl (car entry)) |
414 | (plist-p (if org-store-link-plist t nil)) | |
ff4be292 | 415 | (file (if (and (nth 1 entry) |
621f83e4 CD |
416 | (or (and (stringp (nth 1 entry)) |
417 | (string-match "\\S-" (nth 1 entry))) | |
418 | (functionp (nth 1 entry)))) | |
20908596 CD |
419 | (nth 1 entry) |
420 | org-default-notes-file)) | |
421 | (headline (nth 2 entry)) | |
422 | (v-c (and (> (length kill-ring) 0) (current-kill 0))) | |
423 | (v-x (or (org-get-x-clipboard 'PRIMARY) | |
424 | (org-get-x-clipboard 'CLIPBOARD) | |
425 | (org-get-x-clipboard 'SECONDARY))) | |
b349f79f CD |
426 | (v-t (format-time-string (car org-time-stamp-formats) ct)) |
427 | (v-T (format-time-string (cdr org-time-stamp-formats) ct)) | |
20908596 CD |
428 | (v-u (concat "[" (substring v-t 1 -1) "]")) |
429 | (v-U (concat "[" (substring v-T 1 -1) "]")) | |
c8d0cf5c CD |
430 | ;; `initial' and `annotation' are bound in `remember'. |
431 | ;; But if the property list has them, we prefer those values | |
432 | (v-i (or (plist-get org-store-link-plist :initial) | |
433 | (and (boundp 'initial) initial) | |
434 | "")) | |
435 | (v-a (or (plist-get org-store-link-plist :annotation) | |
436 | (and (boundp 'annotation) annotation) | |
437 | "")) | |
438 | ;; Is the link empty? Then we do not want it... | |
439 | (v-a (if (equal v-a "[[]]") "" v-a)) | |
20908596 CD |
440 | (clipboards (remove nil (list v-i |
441 | (org-get-x-clipboard 'PRIMARY) | |
442 | (org-get-x-clipboard 'CLIPBOARD) | |
443 | (org-get-x-clipboard 'SECONDARY) | |
444 | v-c))) | |
445 | (v-A (if (and v-a | |
446 | (string-match "\\[\\(\\[.*?\\]\\)\\(\\[.*?\\]\\)?\\]" v-a)) | |
447 | (replace-match "[\\1[%^{Link description}]]" nil nil v-a) | |
448 | v-a)) | |
449 | (v-n user-full-name) | |
621f83e4 | 450 | (v-k (if (marker-buffer org-clock-marker) |
ce4fdcb9 | 451 | (org-substring-no-properties org-clock-heading))) |
621f83e4 CD |
452 | (v-K (if (marker-buffer org-clock-marker) |
453 | (org-make-link-string | |
454 | (buffer-file-name (marker-buffer org-clock-marker)) | |
455 | org-clock-heading))) | |
456 | v-I | |
20908596 | 457 | (org-startup-folded nil) |
621f83e4 | 458 | (org-inhibit-startup t) |
20908596 CD |
459 | org-time-was-given org-end-time-was-given x |
460 | prompt completions char time pos default histvar) | |
621f83e4 CD |
461 | |
462 | (when (functionp file) | |
463 | (setq file (funcall file))) | |
c8d0cf5c CD |
464 | (when (functionp headline) |
465 | (setq headline (funcall headline))) | |
20908596 CD |
466 | (when (and file (not (file-name-absolute-p file))) |
467 | (setq file (expand-file-name file org-directory))) | |
621f83e4 | 468 | |
20908596 | 469 | (setq org-store-link-plist |
c8d0cf5c CD |
470 | (plist-put org-store-link-plist :annotation v-a) |
471 | org-store-link-plist | |
472 | (plist-put org-store-link-plist :initial v-i)) | |
473 | ||
20908596 CD |
474 | (unless tpl (setq tpl "") (message "No template") (ding) (sit-for 1)) |
475 | (erase-buffer) | |
476 | (insert (substitute-command-keys | |
477 | (format | |
621f83e4 CD |
478 | "## %s \"%s\" -> \"* %s\" |
479 | ## C-u C-c C-c like C-c C-c, and immediately visit note at target location | |
480 | ## C-0 C-c C-c \"%s\" -> \"* %s\" | |
20908596 | 481 | ## %s to select file and header location interactively. |
ed21c5c8 | 482 | ## C-2 C-c C-c as child (C-3: as sibling) of the currently clocked item |
20908596 | 483 | ## To switch templates, use `\\[org-remember]'. To abort use `C-c C-k'.\n\n" |
621f83e4 | 484 | (if org-remember-store-without-prompt " C-c C-c" " C-1 C-c C-c") |
20908596 CD |
485 | (abbreviate-file-name (or file org-default-notes-file)) |
486 | (or headline "") | |
487 | (or (car org-remember-previous-location) "???") | |
621f83e4 CD |
488 | (or (cdr org-remember-previous-location) "???") |
489 | (if org-remember-store-without-prompt "C-1 C-c C-c" " C-c C-c")))) | |
490 | (insert tpl) | |
621f83e4 | 491 | |
ed21c5c8 CD |
492 | ;; %[] Insert contents of a file. |
493 | (goto-char (point-min)) | |
494 | (while (re-search-forward "%\\[\\(.+\\)\\]" nil t) | |
495 | (unless (org-remember-escaped-%) | |
496 | (let ((start (match-beginning 0)) | |
497 | (end (match-end 0)) | |
498 | (filename (expand-file-name (match-string 1)))) | |
499 | (goto-char start) | |
500 | (delete-region start end) | |
501 | (condition-case error | |
502 | (insert-file-contents filename) | |
503 | (error (insert (format "%%![Couldn't insert %s: %s]" | |
504 | filename error))))))) | |
20908596 | 505 | ;; Simple %-escapes |
ed21c5c8 | 506 | (goto-char (point-min)) |
621f83e4 | 507 | (while (re-search-forward "%\\([tTuUaiAcxkKI]\\)" nil t) |
54a0dee5 CD |
508 | (unless (org-remember-escaped-%) |
509 | (when (and initial (equal (match-string 0) "%i")) | |
510 | (save-match-data | |
511 | (let* ((lead (buffer-substring | |
512 | (point-at-bol) (match-beginning 0)))) | |
513 | (setq v-i (mapconcat 'identity | |
514 | (org-split-string initial "\n") | |
515 | (concat "\n" lead)))))) | |
516 | (replace-match | |
517 | (or (eval (intern (concat "v-" (match-string 1)))) "") | |
518 | t t))) | |
20908596 | 519 | |
20908596 CD |
520 | ;; %() embedded elisp |
521 | (goto-char (point-min)) | |
522 | (while (re-search-forward "%\\((.+)\\)" nil t) | |
54a0dee5 CD |
523 | (unless (org-remember-escaped-%) |
524 | (goto-char (match-beginning 0)) | |
525 | (let ((template-start (point))) | |
526 | (forward-char 1) | |
527 | (let ((result | |
528 | (condition-case error | |
529 | (eval (read (current-buffer))) | |
530 | (error (format "%%![Error: %s]" error))))) | |
531 | (delete-region template-start (point)) | |
532 | (insert result))))) | |
20908596 CD |
533 | |
534 | ;; From the property list | |
535 | (when plist-p | |
536 | (goto-char (point-min)) | |
537 | (while (re-search-forward "%\\(:[-a-zA-Z]+\\)" nil t) | |
54a0dee5 | 538 | (unless (org-remember-escaped-%) |
20908596 CD |
539 | (and (setq x (or (plist-get org-store-link-plist |
540 | (intern (match-string 1))) "")) | |
54a0dee5 | 541 | (replace-match x t t))))) |
20908596 CD |
542 | |
543 | ;; Turn on org-mode in the remember buffer, set local variables | |
ce4fdcb9 | 544 | (let ((org-inhibit-startup t)) (org-mode) (org-remember-mode 1)) |
20908596 CD |
545 | (if (and file (string-match "\\S-" file) (not (file-directory-p file))) |
546 | (org-set-local 'org-default-notes-file file)) | |
b349f79f | 547 | (if headline |
20908596 | 548 | (org-set-local 'org-remember-default-headline headline)) |
8bfe682a CD |
549 | (org-set-local 'org-remember-reference-date |
550 | (list (nth 4 dct) (nth 3 dct) (nth 5 dct))) | |
20908596 CD |
551 | ;; Interactive template entries |
552 | (goto-char (point-min)) | |
621f83e4 | 553 | (while (re-search-forward "%^\\({\\([^}]*\\)}\\)?\\([gGtTuUCLp]\\)?" nil t) |
54a0dee5 CD |
554 | (unless (org-remember-escaped-%) |
555 | (setq char (if (match-end 3) (match-string 3)) | |
556 | prompt (if (match-end 2) (match-string 2))) | |
557 | (goto-char (match-beginning 0)) | |
558 | (replace-match "") | |
559 | (setq completions nil default nil) | |
560 | (when prompt | |
561 | (setq completions (org-split-string prompt "|") | |
562 | prompt (pop completions) | |
563 | default (car completions) | |
564 | histvar (intern (concat | |
565 | "org-remember-template-prompt-history::" | |
566 | (or prompt ""))) | |
567 | completions (mapcar 'list completions))) | |
568 | (cond | |
569 | ((member char '("G" "g")) | |
570 | (let* ((org-last-tags-completion-table | |
571 | (org-global-tags-completion-table | |
572 | (if (equal char "G") (org-agenda-files) (and file (list file))))) | |
573 | (org-add-colon-after-tag-completion t) | |
574 | (ins (org-icompleting-read | |
575 | (if prompt (concat prompt ": ") "Tags: ") | |
576 | 'org-tags-completion-function nil nil nil | |
577 | 'org-tags-history))) | |
578 | (setq ins (mapconcat 'identity | |
afe98dfa | 579 | (org-split-string ins (org-re "[^[:alnum:]_@#%]+")) |
54a0dee5 CD |
580 | ":")) |
581 | (when (string-match "\\S-" ins) | |
582 | (or (equal (char-before) ?:) (insert ":")) | |
583 | (insert ins) | |
584 | (or (equal (char-after) ?:) (insert ":"))))) | |
585 | ((equal char "C") | |
586 | (cond ((= (length clipboards) 1) (insert (car clipboards))) | |
587 | ((> (length clipboards) 1) | |
588 | (insert (read-string "Clipboard/kill value: " | |
589 | (car clipboards) '(clipboards . 1) | |
590 | (car clipboards)))))) | |
591 | ((equal char "L") | |
592 | (cond ((= (length clipboards) 1) | |
593 | (org-insert-link 0 (car clipboards))) | |
594 | ((> (length clipboards) 1) | |
595 | (org-insert-link 0 (read-string "Clipboard/kill value: " | |
596 | (car clipboards) | |
597 | '(clipboards . 1) | |
598 | (car clipboards)))))) | |
599 | ((equal char "p") | |
600 | (let* | |
601 | ((prop (org-substring-no-properties prompt)) | |
602 | (pall (concat prop "_ALL")) | |
603 | (allowed | |
604 | (with-current-buffer | |
8bfe682a CD |
605 | (or (find-buffer-visiting file) |
606 | (find-file-noselect file)) | |
54a0dee5 CD |
607 | (or (cdr (assoc pall org-file-properties)) |
608 | (cdr (assoc pall org-global-properties)) | |
609 | (cdr (assoc pall org-global-properties-fixed))))) | |
610 | (existing (with-current-buffer | |
8bfe682a CD |
611 | (or (find-buffer-visiting file) |
612 | (find-file-noselect file)) | |
54a0dee5 CD |
613 | (mapcar 'list (org-property-values prop)))) |
614 | (propprompt (concat "Value for " prop ": ")) | |
615 | (val (if allowed | |
616 | (org-completing-read | |
617 | propprompt | |
618 | (mapcar 'list (org-split-string allowed "[ \t]+")) | |
619 | nil 'req-match) | |
620 | (org-completing-read-no-i propprompt existing nil nil | |
621 | "" nil "")))) | |
622 | (org-set-property prop val))) | |
623 | (char | |
624 | ;; These are the date/time related ones | |
625 | (setq org-time-was-given (equal (upcase char) char)) | |
626 | (setq time (org-read-date (equal (upcase char) "U") t nil | |
627 | prompt)) | |
628 | (org-insert-time-stamp time org-time-was-given | |
629 | (member char '("u" "U")) | |
630 | nil nil (list org-end-time-was-given))) | |
631 | (t | |
632 | (let (org-completion-use-ido) | |
8bfe682a CD |
633 | (insert (org-without-partial-completion |
634 | (org-completing-read-no-i | |
635 | (concat (if prompt prompt "Enter string") | |
636 | (if default (concat " [" default "]")) | |
637 | ": ") | |
638 | completions nil nil nil histvar default)))))))) | |
54a0dee5 | 639 | |
20908596 CD |
640 | (goto-char (point-min)) |
641 | (if (re-search-forward "%\\?" nil t) | |
642 | (replace-match "") | |
643 | (and (re-search-forward "^[^#\n]" nil t) (backward-char 1)))) | |
ce4fdcb9 | 644 | (let ((org-inhibit-startup t)) (org-mode) (org-remember-mode 1))) |
b349f79f CD |
645 | (when (save-excursion |
646 | (goto-char (point-min)) | |
647 | (re-search-forward "%&" nil t)) | |
648 | (replace-match "") | |
649 | (org-set-local 'org-jump-to-target-location t)) | |
c8d0cf5c CD |
650 | (when org-remember-backup-directory |
651 | (unless (file-directory-p org-remember-backup-directory) | |
652 | (make-directory org-remember-backup-directory)) | |
653 | (org-set-local 'auto-save-file-name-transforms nil) | |
654 | (setq buffer-file-name | |
655 | (expand-file-name | |
656 | (format-time-string "remember-%Y-%m-%d-%H-%M-%S") | |
657 | org-remember-backup-directory)) | |
658 | (save-buffer) | |
659 | (org-set-local 'auto-save-visited-file-name t) | |
660 | (auto-save-mode 1)) | |
20908596 CD |
661 | (when (save-excursion |
662 | (goto-char (point-min)) | |
663 | (re-search-forward "%!" nil t)) | |
664 | (replace-match "") | |
665 | (add-hook 'post-command-hook 'org-remember-finish-immediately 'append))) | |
666 | ||
54a0dee5 CD |
667 | (defun org-remember-escaped-% () |
668 | (if (equal (char-before (match-beginning 0)) ?\\) | |
669 | (progn | |
670 | (delete-region (1- (match-beginning 0)) (match-beginning 0)) | |
671 | t) | |
672 | nil)) | |
673 | ||
674 | ||
20908596 CD |
675 | (defun org-remember-finish-immediately () |
676 | "File remember note immediately. | |
677 | This should be run in `post-command-hook' and will remove itself | |
678 | from that hook." | |
679 | (remove-hook 'post-command-hook 'org-remember-finish-immediately) | |
ce4fdcb9 | 680 | (org-remember-finalize)) |
20908596 | 681 | |
b349f79f CD |
682 | (defun org-remember-visit-immediately () |
683 | "File remember note immediately. | |
684 | This should be run in `post-command-hook' and will remove itself | |
685 | from that hook." | |
686 | (org-remember '(16)) | |
687 | (goto-char (or (text-property-any | |
688 | (point) (save-excursion (org-end-of-subtree t t)) | |
689 | 'org-position-cursor t) | |
690 | (point))) | |
691 | (message "%s" | |
692 | (format | |
ff4be292 | 693 | (substitute-command-keys |
b349f79f CD |
694 | "Restore window configuration with \\[jump-to-register] %c") |
695 | remember-register))) | |
696 | ||
697 | (defvar org-clock-marker) ; Defined in org.el | |
20908596 CD |
698 | (defun org-remember-finalize () |
699 | "Finalize the remember process." | |
ce4fdcb9 CD |
700 | (interactive) |
701 | (unless org-remember-mode | |
702 | (error "This does not seem to be a remember buffer for Org-mode")) | |
703 | (run-hooks 'org-remember-before-finalize-hook) | |
20908596 CD |
704 | (unless (fboundp 'remember-finalize) |
705 | (defalias 'remember-finalize 'remember-buffer)) | |
706 | (when (and org-clock-marker | |
707 | (equal (marker-buffer org-clock-marker) (current-buffer))) | |
b349f79f CD |
708 | ;; the clock is running in this buffer. |
709 | (when (and (equal (marker-buffer org-clock-marker) (current-buffer)) | |
710 | (or (eq org-remember-clock-out-on-exit t) | |
711 | (and org-remember-clock-out-on-exit | |
712 | (y-or-n-p "The clock is running in this buffer. Clock out now? ")))) | |
713 | (let (org-log-note-clock-out) (org-clock-out)))) | |
20908596 | 714 | (when buffer-file-name |
c8d0cf5c | 715 | (do-auto-save)) |
20908596 CD |
716 | (remember-finalize)) |
717 | ||
ce4fdcb9 CD |
718 | (defun org-remember-kill () |
719 | "Abort the current remember process." | |
720 | (interactive) | |
721 | (let ((org-note-abort t)) | |
722 | (org-remember-finalize))) | |
723 | ||
20908596 CD |
724 | ;;;###autoload |
725 | (defun org-remember (&optional goto org-force-remember-template-char) | |
726 | "Call `remember'. If this is already a remember buffer, re-apply template. | |
727 | If there is an active region, make sure remember uses it as initial content | |
728 | of the remember buffer. | |
729 | ||
86fbb8ca CD |
730 | When called interactively with a \\[universal-argument] \ |
731 | prefix argument GOTO, don't remember | |
20908596 | 732 | anything, just go to the file/headline where the selected template usually |
86fbb8ca CD |
733 | stores its notes. With a double prefix argument \ |
734 | \\[universal-argument] \\[universal-argument], go to the last | |
20908596 CD |
735 | note stored by remember. |
736 | ||
737 | Lisp programs can set ORG-FORCE-REMEMBER-TEMPLATE-CHAR to a character | |
738 | associated with a template in `org-remember-templates'." | |
739 | (interactive "P") | |
621f83e4 | 740 | (org-require-remember) |
20908596 CD |
741 | (cond |
742 | ((equal goto '(4)) (org-go-to-remember-target)) | |
743 | ((equal goto '(16)) (org-remember-goto-last-stored)) | |
744 | (t | |
745 | ;; set temporary variables that will be needed in | |
746 | ;; `org-select-remember-template' | |
747 | (setq org-select-template-temp-major-mode major-mode) | |
748 | (setq org-select-template-original-buffer (current-buffer)) | |
ce4fdcb9 | 749 | (if org-remember-mode |
20908596 CD |
750 | (progn |
751 | (when (< (length org-remember-templates) 2) | |
752 | (error "No other template available")) | |
753 | (erase-buffer) | |
754 | (let ((annotation (plist-get org-store-link-plist :annotation)) | |
755 | (initial (plist-get org-store-link-plist :initial))) | |
756 | (org-remember-apply-template)) | |
757 | (message "Press C-c C-c to remember data")) | |
758 | (if (org-region-active-p) | |
759 | (org-do-remember (buffer-substring (point) (mark))) | |
760 | (org-do-remember)))))) | |
761 | ||
b349f79f CD |
762 | (defvar org-remember-last-stored-marker (make-marker) |
763 | "Marker pointing to the entry most recently stored with `org-remember'.") | |
764 | ||
20908596 CD |
765 | (defun org-remember-goto-last-stored () |
766 | "Go to the location where the last remember note was stored." | |
767 | (interactive) | |
b349f79f CD |
768 | (org-goto-marker-or-bmk org-remember-last-stored-marker |
769 | "org-remember-last-stored") | |
20908596 CD |
770 | (message "This is the last note stored by remember")) |
771 | ||
772 | (defun org-go-to-remember-target (&optional template-key) | |
773 | "Go to the target location of a remember template. | |
774 | The user is queried for the template." | |
775 | (interactive) | |
776 | (let* (org-select-template-temp-major-mode | |
777 | (entry (org-select-remember-template template-key)) | |
778 | (file (nth 1 entry)) | |
779 | (heading (nth 2 entry)) | |
780 | visiting) | |
781 | (unless (and file (stringp file) (string-match "\\S-" file)) | |
782 | (setq file org-default-notes-file)) | |
783 | (when (and file (not (file-name-absolute-p file))) | |
784 | (setq file (expand-file-name file org-directory))) | |
785 | (unless (and heading (stringp heading) (string-match "\\S-" heading)) | |
786 | (setq heading org-remember-default-headline)) | |
787 | (setq visiting (org-find-base-buffer-visiting file)) | |
788 | (if (not visiting) (find-file-noselect file)) | |
c3313451 | 789 | (switch-to-buffer (or visiting (get-file-buffer file))) |
20908596 CD |
790 | (widen) |
791 | (goto-char (point-min)) | |
792 | (if (re-search-forward | |
8d642074 | 793 | (format org-complex-heading-regexp-format (regexp-quote heading)) |
20908596 CD |
794 | nil t) |
795 | (goto-char (match-beginning 0)) | |
796 | (error "Target headline not found: %s" heading)))) | |
797 | ||
c8d0cf5c CD |
798 | ;; FIXME (bzg): let's clean up of final empty lines happen only once |
799 | ;; (see the org-remember-delete-empty-lines-at-end option below) | |
20908596 CD |
800 | ;;;###autoload |
801 | (defun org-remember-handler () | |
802 | "Store stuff from remember.el into an org file. | |
621f83e4 CD |
803 | When the template has specified a file and a headline, the entry is filed |
804 | there, or in the location defined by `org-default-notes-file' and | |
805 | `org-remember-default-headline'. | |
86fbb8ca | 806 | \\<org-remember-mode-map> |
621f83e4 | 807 | If no defaults have been defined, or if the current prefix argument |
86fbb8ca | 808 | is 1 (using C-1 \\[org-remember-finalize] to exit remember), an interactive |
621f83e4 CD |
809 | process is used to select the target location. |
810 | ||
86fbb8ca CD |
811 | When the prefix is 0 (i.e. when remember is exited with \ |
812 | C-0 \\[org-remember-finalize]), | |
621f83e4 CD |
813 | the entry is filed to the same location as the previous note. |
814 | ||
86fbb8ca CD |
815 | When the prefix is 2 (i.e. when remember is exited with \ |
816 | C-2 \\[org-remember-finalize]), | |
33306645 | 817 | the entry is filed as a subentry of the entry where the clock is |
621f83e4 CD |
818 | currently running. |
819 | ||
86fbb8ca CD |
820 | When \\[universal-argument] has been used as prefix argument, the |
821 | note is stored and Emacs moves point to the new location of the | |
822 | note, so that editing can be continued there (similar to | |
823 | inserting \"%&\" into the template). | |
621f83e4 CD |
824 | |
825 | Before storing the note, the function ensures that the text has an | |
826 | org-mode-style headline, i.e. a first line that starts with | |
827 | a \"*\". If not, a headline is constructed from the current date and | |
828 | some additional data. | |
20908596 CD |
829 | |
830 | If the variable `org-adapt-indentation' is non-nil, the entire text is | |
831 | also indented so that it starts in the same column as the headline | |
832 | \(i.e. after the stars). | |
833 | ||
834 | See also the variable `org-reverse-note-order'." | |
621f83e4 CD |
835 | (when (and (equal current-prefix-arg 2) |
836 | (not (marker-buffer org-clock-marker))) | |
93b62de8 | 837 | (error "No running clock")) |
b349f79f CD |
838 | (when (org-bound-and-true-p org-jump-to-target-location) |
839 | (let* ((end (min (point-max) (1+ (point)))) | |
840 | (beg (point))) | |
841 | (if (= end beg) (setq beg (1- beg))) | |
842 | (put-text-property beg end 'org-position-cursor t))) | |
20908596 CD |
843 | (goto-char (point-min)) |
844 | (while (looking-at "^[ \t]*\n\\|^##.*\n") | |
845 | (replace-match "")) | |
c8d0cf5c CD |
846 | (when org-remember-delete-empty-lines-at-end |
847 | (goto-char (point-max)) | |
848 | (beginning-of-line 1) | |
849 | (while (and (looking-at "[ \t]*$\\|##.*") (> (point) 1)) | |
850 | (delete-region (1- (point)) (point-max)) | |
851 | (beginning-of-line 1))) | |
20908596 | 852 | (catch 'quit |
c8d0cf5c | 853 | (if org-note-abort (throw 'quit t)) |
b349f79f | 854 | (let* ((visitp (org-bound-and-true-p org-jump-to-target-location)) |
c8d0cf5c CD |
855 | (backup-file |
856 | (and buffer-file-name | |
857 | (equal (file-name-directory buffer-file-name) | |
858 | (file-name-as-directory | |
859 | (expand-file-name org-remember-backup-directory))) | |
860 | (string-match "^remember-[0-9]\\{4\\}" | |
861 | (file-name-nondirectory buffer-file-name)) | |
862 | buffer-file-name)) | |
863 | ||
864 | (dummy | |
865 | (unless (string-match "\\S-" (buffer-string)) | |
866 | (message "Nothing to remember") | |
867 | (and backup-file | |
868 | (ignore-errors | |
869 | (delete-file backup-file) | |
870 | (delete-file (concat backup-file "~")))) | |
871 | (set-buffer-modified-p nil) | |
872 | (throw 'quit t))) | |
8bfe682a | 873 | (reference-date org-remember-reference-date) |
621f83e4 CD |
874 | (previousp (and (member current-prefix-arg '((16) 0)) |
875 | org-remember-previous-location)) | |
876 | (clockp (equal current-prefix-arg 2)) | |
ed21c5c8 | 877 | (clocksp (equal current-prefix-arg 3)) |
621f83e4 | 878 | (fastp (org-xor (equal current-prefix-arg 1) |
20908596 CD |
879 | org-remember-store-without-prompt)) |
880 | (file (cond | |
881 | (fastp org-default-notes-file) | |
882 | ((and (eq org-remember-interactive-interface 'refile) | |
883 | org-refile-targets) | |
884 | org-default-notes-file) | |
621f83e4 | 885 | ((not previousp) |
20908596 CD |
886 | (org-get-org-file)))) |
887 | (heading org-remember-default-headline) | |
888 | (visiting (and file (org-find-base-buffer-visiting file))) | |
889 | (org-startup-folded nil) | |
890 | (org-startup-align-all-tables nil) | |
891 | (org-goto-start-pos 1) | |
c8d0cf5c | 892 | spos exitcmd level reversed txt text-before-node-creation) |
621f83e4 CD |
893 | (when (equal current-prefix-arg '(4)) |
894 | (setq visitp t)) | |
895 | (when previousp | |
896 | (setq file (car org-remember-previous-location) | |
93b62de8 | 897 | visiting (and file (org-find-base-buffer-visiting file)) |
621f83e4 CD |
898 | heading (cdr org-remember-previous-location) |
899 | fastp t)) | |
ed21c5c8 | 900 | (when (or clockp clocksp) |
621f83e4 | 901 | (setq file (buffer-file-name (marker-buffer org-clock-marker)) |
93b62de8 | 902 | visiting (and file (org-find-base-buffer-visiting file)) |
621f83e4 CD |
903 | heading org-clock-heading-for-remember |
904 | fastp t)) | |
20908596 | 905 | (setq current-prefix-arg nil) |
20908596 CD |
906 | ;; Modify text so that it becomes a nice subtree which can be inserted |
907 | ;; into an org tree. | |
c8d0cf5c CD |
908 | (when org-remember-delete-empty-lines-at-end |
909 | (goto-char (point-min)) | |
910 | (if (re-search-forward "[ \t\n]+\\'" nil t) | |
911 | ;; remove empty lines at end | |
912 | (replace-match ""))) | |
b349f79f | 913 | (goto-char (point-min)) |
8bfe682a | 914 | (setq text-before-node-creation (buffer-string)) |
b349f79f CD |
915 | (unless (looking-at org-outline-regexp) |
916 | ;; add a headline | |
917 | (insert (concat "* " (current-time-string) | |
918 | " (" (remember-buffer-desc) ")\n")) | |
919 | (backward-char 1) | |
920 | (when org-adapt-indentation | |
921 | (while (re-search-forward "^" nil t) | |
922 | (insert " ")))) | |
c8d0cf5c CD |
923 | ;; Delete final empty lines |
924 | (when org-remember-delete-empty-lines-at-end | |
925 | (goto-char (point-min)) | |
926 | (if (re-search-forward "\n[ \t]*\n[ \t\n]*\\'" nil t) | |
927 | (replace-match "\n\n") | |
928 | (if (re-search-forward "[ \t\n]*\\'") | |
929 | (replace-match "\n")))) | |
b349f79f CD |
930 | (goto-char (point-min)) |
931 | (setq txt (buffer-string)) | |
932 | (org-save-markers-in-region (point-min) (point-max)) | |
c8d0cf5c | 933 | (set-buffer-modified-p nil) |
20908596 CD |
934 | (when (and (eq org-remember-interactive-interface 'refile) |
935 | (not fastp)) | |
936 | (org-refile nil (or visiting (find-file-noselect file))) | |
b349f79f | 937 | (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit-immediately)) |
ce4fdcb9 CD |
938 | (save-excursion |
939 | (bookmark-jump "org-refile-last-stored") | |
940 | (bookmark-set "org-remember-last-stored") | |
941 | (move-marker org-remember-last-stored-marker (point))) | |
20908596 CD |
942 | (throw 'quit t)) |
943 | ;; Find the file | |
bb31cb31 | 944 | (with-current-buffer (or visiting (find-file-noselect file)) |
c8d0cf5c CD |
945 | (unless (or (org-mode-p) (member heading '(top bottom))) |
946 | (error "Target files for notes must be in Org-mode if not filing to top/bottom")) | |
20908596 CD |
947 | (save-excursion |
948 | (save-restriction | |
949 | (widen) | |
20908596 CD |
950 | (setq reversed (org-notes-order-reversed-p)) |
951 | ||
952 | ;; Find the default location | |
b349f79f CD |
953 | (when heading |
954 | (cond | |
c8d0cf5c CD |
955 | ((not (org-mode-p)) |
956 | (if (eq heading 'top) | |
957 | (goto-char (point-min)) | |
958 | (goto-char (point-max)) | |
959 | (or (bolp) (newline))) | |
960 | (insert text-before-node-creation) | |
961 | (when remember-save-after-remembering | |
962 | (save-buffer) | |
963 | (if (not visiting) (kill-buffer (current-buffer)))) | |
964 | (throw 'quit t)) | |
b349f79f CD |
965 | ((eq heading 'top) |
966 | (goto-char (point-min)) | |
967 | (or (looking-at org-outline-regexp) | |
968 | (re-search-forward org-outline-regexp nil t)) | |
969 | (setq org-goto-start-pos (or (match-beginning 0) (point-min)))) | |
970 | ((eq heading 'bottom) | |
971 | (goto-char (point-max)) | |
b349f79f CD |
972 | (or (bolp) (newline)) |
973 | (setq org-goto-start-pos (point))) | |
8bfe682a CD |
974 | ((eq heading 'date-tree) |
975 | (org-datetree-find-date-create reference-date) | |
976 | (setq reversed nil) | |
977 | (setq org-goto-start-pos (point))) | |
b349f79f CD |
978 | ((and (stringp heading) (string-match "\\S-" heading)) |
979 | (goto-char (point-min)) | |
980 | (if (re-search-forward | |
8d642074 CD |
981 | (format org-complex-heading-regexp-format |
982 | (regexp-quote heading)) | |
b349f79f CD |
983 | nil t) |
984 | (setq org-goto-start-pos (match-beginning 0)) | |
985 | (when fastp | |
986 | (goto-char (point-max)) | |
987 | (unless (bolp) (newline)) | |
988 | (insert "* " heading "\n") | |
989 | (setq org-goto-start-pos (point-at-bol 0))))) | |
990 | (t (goto-char (point-min)) (setq org-goto-start-pos (point) | |
991 | heading 'top)))) | |
20908596 CD |
992 | |
993 | ;; Ask the User for a location, using the appropriate interface | |
994 | (cond | |
b349f79f CD |
995 | ((and fastp (memq heading '(top bottom))) |
996 | (setq spos org-goto-start-pos | |
621f83e4 | 997 | exitcmd (if (eq heading 'top) 'left nil))) |
20908596 CD |
998 | (fastp (setq spos org-goto-start-pos |
999 | exitcmd 'return)) | |
1000 | ((eq org-remember-interactive-interface 'outline) | |
1001 | (setq spos (org-get-location (current-buffer) | |
1002 | org-remember-help) | |
1003 | exitcmd (cdr spos) | |
1004 | spos (car spos))) | |
1005 | ((eq org-remember-interactive-interface 'outline-path-completion) | |
1006 | (let ((org-refile-targets '((nil . (:maxlevel . 10)))) | |
1007 | (org-refile-use-outline-path t)) | |
3ab2c837 | 1008 | (setq spos (org-refile-get-location "Heading") |
20908596 CD |
1009 | exitcmd 'return |
1010 | spos (nth 3 spos)))) | |
1011 | (t (error "This should not happen"))) | |
1012 | (if (not spos) (throw 'quit nil)) ; return nil to show we did | |
1013 | ; not handle this note | |
b349f79f | 1014 | (and visitp (run-with-idle-timer 0.01 nil 'org-remember-visit-immediately)) |
20908596 CD |
1015 | (goto-char spos) |
1016 | (cond ((org-on-heading-p t) | |
1017 | (org-back-to-heading t) | |
1018 | (setq level (funcall outline-level)) | |
1019 | (cond | |
1020 | ((eq exitcmd 'return) | |
1021 | ;; sublevel of current | |
1022 | (setq org-remember-previous-location | |
1023 | (cons (abbreviate-file-name file) | |
1024 | (org-get-heading 'notags))) | |
1025 | (if reversed | |
1026 | (outline-next-heading) | |
1027 | (org-end-of-subtree t) | |
1028 | (if (not (bolp)) | |
1029 | (if (looking-at "[ \t]*\n") | |
1030 | (beginning-of-line 2) | |
1031 | (end-of-line 1) | |
1032 | (insert "\n")))) | |
ed21c5c8 CD |
1033 | (org-paste-subtree (if clocksp |
1034 | level | |
1035 | (org-get-valid-level level 1)) txt) | |
b349f79f | 1036 | (and org-auto-align-tags (org-set-tags nil t)) |
20908596 | 1037 | (bookmark-set "org-remember-last-stored") |
b349f79f | 1038 | (move-marker org-remember-last-stored-marker (point))) |
20908596 CD |
1039 | ((eq exitcmd 'left) |
1040 | ;; before current | |
b349f79f CD |
1041 | (org-paste-subtree level txt) |
1042 | (and org-auto-align-tags (org-set-tags nil t)) | |
20908596 | 1043 | (bookmark-set "org-remember-last-stored") |
b349f79f | 1044 | (move-marker org-remember-last-stored-marker (point))) |
20908596 CD |
1045 | ((eq exitcmd 'right) |
1046 | ;; after current | |
1047 | (org-end-of-subtree t) | |
b349f79f CD |
1048 | (org-paste-subtree level txt) |
1049 | (and org-auto-align-tags (org-set-tags nil t)) | |
20908596 | 1050 | (bookmark-set "org-remember-last-stored") |
b349f79f | 1051 | (move-marker org-remember-last-stored-marker (point))) |
20908596 CD |
1052 | (t (error "This should not happen")))) |
1053 | ||
621f83e4 CD |
1054 | ((eq heading 'bottom) |
1055 | (org-paste-subtree 1 txt) | |
1056 | (and org-auto-align-tags (org-set-tags nil t)) | |
1057 | (bookmark-set "org-remember-last-stored") | |
1058 | (move-marker org-remember-last-stored-marker (point))) | |
1059 | ||
20908596 CD |
1060 | ((and (bobp) (not reversed)) |
1061 | ;; Put it at the end, one level below level 1 | |
1062 | (save-restriction | |
1063 | (widen) | |
1064 | (goto-char (point-max)) | |
1065 | (if (not (bolp)) (newline)) | |
b349f79f CD |
1066 | (org-paste-subtree (org-get-valid-level 1 1) txt) |
1067 | (and org-auto-align-tags (org-set-tags nil t)) | |
20908596 | 1068 | (bookmark-set "org-remember-last-stored") |
b349f79f | 1069 | (move-marker org-remember-last-stored-marker (point)))) |
20908596 CD |
1070 | |
1071 | ((and (bobp) reversed) | |
1072 | ;; Put it at the start, as level 1 | |
1073 | (save-restriction | |
1074 | (widen) | |
1075 | (goto-char (point-min)) | |
3ab2c837 | 1076 | (re-search-forward org-outline-regexp-bol nil t) |
20908596 | 1077 | (beginning-of-line 1) |
b349f79f CD |
1078 | (org-paste-subtree 1 txt) |
1079 | (and org-auto-align-tags (org-set-tags nil t)) | |
20908596 | 1080 | (bookmark-set "org-remember-last-stored") |
b349f79f | 1081 | (move-marker org-remember-last-stored-marker (point)))) |
20908596 CD |
1082 | (t |
1083 | ;; Put it right there, with automatic level determined by | |
1084 | ;; org-paste-subtree or from prefix arg | |
20908596 CD |
1085 | (org-paste-subtree |
1086 | (if (numberp current-prefix-arg) current-prefix-arg) | |
b349f79f CD |
1087 | txt) |
1088 | (and org-auto-align-tags (org-set-tags nil t)) | |
1089 | (bookmark-set "org-remember-last-stored") | |
1090 | (move-marker org-remember-last-stored-marker (point)))) | |
1091 | ||
20908596 CD |
1092 | (when remember-save-after-remembering |
1093 | (save-buffer) | |
b349f79f CD |
1094 | (if (and (not visiting) |
1095 | (not (equal (marker-buffer org-clock-marker) | |
1096 | (current-buffer)))) | |
c8d0cf5c CD |
1097 | (kill-buffer (current-buffer)))) |
1098 | (when org-remember-auto-remove-backup-files | |
1099 | (when backup-file | |
1100 | (ignore-errors | |
1101 | (delete-file backup-file) | |
1102 | (delete-file (concat backup-file "~")))) | |
1103 | (when org-remember-backup-directory | |
1104 | (let ((n (length | |
1105 | (directory-files | |
1106 | org-remember-backup-directory nil | |
1107 | "^remember-.*[0-9]$")))) | |
54a0dee5 CD |
1108 | (when (and org-remember-warn-about-backups |
1109 | (> n 0)) | |
c8d0cf5c CD |
1110 | (message |
1111 | "%d backup files (unfinished remember calls) in %s" | |
1112 | n org-remember-backup-directory)))))))))) | |
20908596 CD |
1113 | |
1114 | t) ;; return t to indicate that we took care of this note. | |
1115 | ||
20908596 CD |
1116 | (defun org-do-remember (&optional initial) |
1117 | "Call remember." | |
1118 | (remember initial)) | |
1119 | ||
621f83e4 CD |
1120 | (defun org-require-remember () |
1121 | "Make sure remember is loaded, or install our own emergency version of it." | |
1122 | (condition-case nil | |
1123 | (require 'remember) | |
1124 | (error | |
c7015153 | 1125 | ;; Let's install our own micro version of remember |
621f83e4 CD |
1126 | (defvar remember-register ?R) |
1127 | (defvar remember-mode-hook nil) | |
1128 | (defvar remember-handler-functions nil) | |
1129 | (defvar remember-buffer "*Remember*") | |
1130 | (defvar remember-save-after-remembering t) | |
1131 | (defvar remember-annotation-functions '(buffer-file-name)) | |
1132 | (defun remember-finalize () | |
1133 | (run-hook-with-args-until-success 'remember-handler-functions) | |
1134 | (when (equal remember-buffer (buffer-name)) | |
1135 | (kill-buffer (current-buffer)) | |
1136 | (jump-to-register remember-register))) | |
1137 | (defun remember-mode () | |
1138 | (fundamental-mode) | |
1139 | (setq mode-name "Remember") | |
1140 | (run-hooks 'remember-mode-hook)) | |
1141 | (defun remember (&optional initial) | |
1142 | (window-configuration-to-register remember-register) | |
1143 | (let* ((annotation (run-hook-with-args-until-success | |
1144 | 'remember-annotation-functions))) | |
1145 | (switch-to-buffer-other-window (get-buffer-create remember-buffer)) | |
1146 | (remember-mode))) | |
1147 | (defun remember-buffer-desc () | |
1148 | (buffer-substring (point-min) (save-excursion (goto-char (point-min)) | |
1149 | (point-at-eol))))))) | |
1150 | ||
20908596 CD |
1151 | (provide 'org-remember) |
1152 | ||
5b409b39 | 1153 | |
b349f79f CD |
1154 | |
1155 | ;;; org-remember.el ends here |