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