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