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