Commit | Line | Data |
---|---|---|
15f3eb73 MO |
1 | ;;; remember --- a mode for quickly jotting down things to remember |
2 | ||
ba318903 | 3 | ;; Copyright (C) 1999-2001, 2003-2014 Free Software Foundation, Inc. |
15f3eb73 MO |
4 | |
5 | ;; Author: John Wiegley <johnw@gnu.org> | |
95160c90 | 6 | ;; Maintainer: emacs-devel@gnu.org |
15f3eb73 | 7 | ;; Created: 29 Mar 1999 |
62f01d5e | 8 | ;; Version: 2.0 |
15f3eb73 MO |
9 | ;; Keywords: data memory todo pim |
10 | ;; URL: http://gna.org/projects/remember-el/ | |
11 | ||
12 | ;; This file is part of GNU Emacs. | |
13 | ||
1fecc8fe | 14 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
15f3eb73 | 15 | ;; it under the terms of the GNU General Public License as published by |
1fecc8fe GM |
16 | ;; the Free Software Foundation, either version 3 of the License, or |
17 | ;; (at your option) any later version. | |
15f3eb73 MO |
18 | |
19 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | ;; GNU General Public License for more details. | |
23 | ||
24 | ;; You should have received a copy of the GNU General Public License | |
1fecc8fe | 25 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
15f3eb73 MO |
26 | |
27 | ;;; Commentary: | |
28 | ||
77210f1e | 29 | ;; * The idea |
15f3eb73 MO |
30 | ;; |
31 | ;; Todo lists, schedules, phone databases... everything we use | |
32 | ;; databases for is really just a way to extend the power of our | |
33 | ;; memory. To be able to remember what our conscious mind may not | |
34 | ;; currently have access to. | |
35 | ;; | |
36 | ;; There are many different databases out there -- and good ones -- | |
37 | ;; which this mode is not trying to replace. Rather, it's how that | |
38 | ;; data gets there that's the question. Most of the time, we just | |
39 | ;; want to say "Remember so-and-so's phone number, or that I have to | |
40 | ;; buy dinner for the cats tonight." That's the FACT. How it's | |
41 | ;; stored is really the computer's problem. But at this point in | |
42 | ;; time, it's most definitely also the user's problem, and sometimes | |
43 | ;; so laboriously so that people just let data slip, rather than | |
44 | ;; expend the effort to record it. | |
45 | ;; | |
46 | ;; "Remember" is a mode for remembering data. It uses whatever | |
47 | ;; back-end is appropriate to record and correlate the data, but it's | |
48 | ;; main intention is to allow you to express as _little_ structure as | |
49 | ;; possible up front. If you later want to express more powerful | |
50 | ;; relationships between your data, or state assumptions that were at | |
51 | ;; first too implicit to be recognized, you can "study" the data later | |
52 | ;; and rearrange it. But the initial "just remember this" impulse | |
53 | ;; should be as close to simply throwing the data at Emacs as | |
54 | ;; possible. | |
55 | ;; | |
77210f1e | 56 | ;; * Implementation |
15f3eb73 MO |
57 | ;; |
58 | ;; Hyperbole, as a data presentation tool, always struck me as being | |
59 | ;; very powerful, but it seemed to require a lot of "front-end" work | |
60 | ;; before that data was really available. The problem with BBDB, or | |
61 | ;; keeping up a Bibl-mode file, is that you have to use different | |
62 | ;; functions to record the data, and it always takes time to stop what | |
63 | ;; you're doing, format the data in the manner expected by that | |
64 | ;; particular data interface, and then resume your work. | |
65 | ;; | |
66 | ;; With "remember", you just hit `M-x remember' (you'd probably want | |
67 | ;; to bind this to an easily accessible keystroke, like C-x M-r), slam | |
68 | ;; in your text however you like, and then hit C-c C-c. It will file | |
69 | ;; the data away for later retrieval, and possibly indexing. | |
70 | ;; | |
71 | ;; Indexing is to data what "studying" is in the real world. What you | |
72 | ;; do when you study (or lucubrate, for some of us) is to realize | |
73 | ;; certain relationships implicit in the data, so that you can make | |
74 | ;; use of those relationships. Expressing that a certain quote you | |
75 | ;; remembered was a religious quote, and that you want the ability to | |
76 | ;; pull up all quotes of a religious nature, is what studying does. | |
77 | ;; This is a more labor intensive task than the original remembering | |
78 | ;; of the data, and it's typical in real life to set aside a special | |
79 | ;; period of time for doing this work. | |
80 | ;; | |
81 | ;; "Remember" works in the same way. When you enter data, either by | |
82 | ;; typing it into a buffer, or using the contents of the selected | |
83 | ;; region, it will store that data -- unindexed, uninterpreted -- in a | |
84 | ;; data pool. It will also try to remember as much context | |
85 | ;; information as possible (any text properties that were set, where | |
86 | ;; you copied it from, when, how, etc). Later, you can walk through | |
87 | ;; your accumulated set of data (both organized, and unorganized) and | |
88 | ;; easily begin moving things around, and making annotations that will | |
89 | ;; express the full meaning of that data, as far as you know it. | |
90 | ;; | |
91 | ;; Obviously this latter stage is more user-interface intensive, and | |
92 | ;; it would be nice if "remember" could do it as elegantly as | |
93 | ;; possible, rather than requiring a billion keystrokes to reorganize | |
94 | ;; your hierarchy. Well, as the future arrives, hopefully experience | |
95 | ;; and user feedback will help to make this as intuitive a tool as | |
96 | ;; possible. | |
97 | ;; | |
77210f1e | 98 | ;; * Future Goals |
15f3eb73 MO |
99 | ;; |
100 | ;; This tool hopes to track (and by doing it with as little new code | |
101 | ;; as possible): | |
102 | ;; | |
103 | ;; - The raw data that gets entered | |
104 | ;; | |
105 | ;; - The relationships between that data (either determined | |
106 | ;; implicitly by parsing the input, or explicitly by the user's | |
107 | ;; studying the data). | |
108 | ;; | |
109 | ;; - Revisioning of the data | |
110 | ;; | |
111 | ;; - Where it came from, and any context information that can be | |
112 | ;; programmatically determined. | |
113 | ;; | |
114 | ;; - Allowing particular views of the initially amorphous data pool | |
115 | ;; (ala the Xanadu concept). | |
116 | ;; | |
91af3942 | 117 | ;; - Storage of the data in a manner most appropriate to that data, |
15f3eb73 MO |
118 | ;; such as keeping address-book type information in BBDB, etc. |
119 | ;; | |
77210f1e | 120 | ;; * Using "remember" |
15f3eb73 | 121 | ;; |
ece4bae5 | 122 | ;; As a rough beginning, what I do is to keep my `remember-data-file' in |
15f3eb73 MO |
123 | ;; outline-mode format, with a final entry called "* Raw data". Then, |
124 | ;; at intervals, I can move the data that gets appended there into | |
125 | ;; other places. But certainly this should evolve into an intuitive | |
126 | ;; mechanism for shuffling data off to its appropriate corner of the | |
127 | ;; universe. | |
128 | ;; | |
77210f1e MO |
129 | ;; To map the primary remember function to the keystroke F8, do the |
130 | ;; following. | |
15f3eb73 | 131 | ;; |
77210f1e | 132 | ;; (autoload 'remember "remember" nil t) |
15f3eb73 | 133 | ;; |
77210f1e | 134 | ;; (define-key global-map [f8] 'remember) |
15f3eb73 | 135 | ;; |
77210f1e | 136 | ;; * Feedback |
15f3eb73 MO |
137 | ;; |
138 | ;; If Emacs could become a more intelligent data store, where | |
139 | ;; brainstorming would focus on the IDEAS involved -- rather than the | |
140 | ;; structuring and format of those ideas, or having to stop your | |
141 | ;; current flow of work in order to record them -- it would map much | |
142 | ;; more closely to how the mind (well, at least mine) works, and hence | |
143 | ;; would eliminate that very manual-ness which computers from the very | |
144 | ;; beginning have been championed as being able to reduce. | |
145 | ;; | |
146 | ;; Have you ever noticed that having a laptop to write on doesn't | |
147 | ;; _actually_ increase the amount of quality material that you turn | |
148 | ;; out, in the long run? Perhaps its because the time we save | |
149 | ;; electronically in one way, we're losing electronically in another; | |
150 | ;; the tool should never dominate one's focus. As the mystic | |
151 | ;; Faridu'd-Din `Attar wrote: "Be occupied as little as possible with | |
152 | ;; things of the outer world but much with things of the inner world; | |
153 | ;; then right action will overcome inaction." | |
3728bf03 MO |
154 | ;; |
155 | ;; * Diary integration | |
156 | ;; | |
157 | ;; To use, add the following to your .emacs: | |
158 | ;; | |
159 | ;; ;; This should be before other entries that may return t | |
160 | ;; (add-to-list 'remember-handler-functions 'remember-diary-extract-entries) | |
161 | ;; | |
162 | ;; This module recognizes entries of the form | |
163 | ;; | |
164 | ;; DIARY: .... | |
165 | ;; | |
166 | ;; and puts them in your ~/.diary (or remember-diary-file) together | |
167 | ;; with an annotation. Dates in the form YYYY.MM.DD are converted to | |
168 | ;; YYYY-MM-DD so that diary can understand them. | |
169 | ;; | |
170 | ;; For example: | |
171 | ;; | |
172 | ;; DIARY: 2003.08.12 Sacha's birthday | |
173 | ;; | |
174 | ;; is stored as | |
175 | ;; | |
176 | ;; 2003.08.12 Sacha's birthday | |
15f3eb73 MO |
177 | |
178 | ;;; History: | |
179 | ||
180 | ;;; Code: | |
181 | ||
62f01d5e | 182 | (defconst remember-version "2.0" |
15f3eb73 MO |
183 | "This version of remember.") |
184 | ||
185 | (defgroup remember nil | |
186 | "A mode to remember information." | |
187 | :group 'data) | |
188 | ||
189 | ;;; User Variables: | |
190 | ||
191 | (defcustom remember-mode-hook nil | |
192 | "Functions run upon entering `remember-mode'." | |
193 | :type 'hook | |
e0628060 | 194 | :options '(flyspell-mode turn-on-auto-fill org-remember-apply-template) |
15f3eb73 MO |
195 | :group 'remember) |
196 | ||
197 | (defcustom remember-in-new-frame nil | |
198 | "Non-nil means use a separate frame for capturing remember data." | |
199 | :type 'boolean | |
200 | :group 'remember) | |
201 | ||
202 | (defcustom remember-register ?R | |
203 | "The register in which the window configuration is stored." | |
204 | :type 'character | |
205 | :group 'remember) | |
206 | ||
207 | (defcustom remember-filter-functions nil | |
7ee68ed5 | 208 | "Functions run to filter remember data. |
15f3eb73 MO |
209 | All functions are run in the remember buffer." |
210 | :type 'hook | |
211 | :group 'remember) | |
212 | ||
213 | (defcustom remember-handler-functions '(remember-append-to-file) | |
7ee68ed5 | 214 | "Functions run to process remember data. |
15f3eb73 MO |
215 | Each function is called with the current buffer narrowed to what the |
216 | user wants remembered. | |
217 | If any function returns non-nil, the data is assumed to have been | |
1ffefcf9 | 218 | recorded somewhere by that function." |
15f3eb73 | 219 | :type 'hook |
e0628060 MO |
220 | :options '(remember-store-in-mailbox |
221 | remember-append-to-file | |
1ffefcf9 | 222 | remember-store-in-files |
e0628060 MO |
223 | remember-diary-extract-entries |
224 | org-remember-handler) | |
15f3eb73 MO |
225 | :group 'remember) |
226 | ||
227 | (defcustom remember-all-handler-functions nil | |
7ee68ed5 | 228 | "If non-nil every function in `remember-handler-functions' is called." |
15f3eb73 MO |
229 | :type 'boolean |
230 | :group 'remember) | |
231 | ||
95160c90 GM |
232 | ;; See below for more user variables. |
233 | ||
15f3eb73 MO |
234 | ;;; Internal Variables: |
235 | ||
236 | (defvar remember-buffer "*Remember*" | |
237 | "The name of the remember data entry buffer.") | |
238 | ||
239 | (defcustom remember-save-after-remembering t | |
7ee68ed5 | 240 | "Non-nil means automatically save after remembering." |
15f3eb73 MO |
241 | :type 'boolean |
242 | :group 'remember) | |
243 | ||
244 | ;;; User Functions: | |
245 | ||
77210f1e MO |
246 | (defcustom remember-annotation-functions '(buffer-file-name) |
247 | "Hook that returns an annotation to be inserted into the remember buffer." | |
15f3eb73 | 248 | :type 'hook |
e0628060 | 249 | :options '(org-remember-annotation buffer-file-name) |
15f3eb73 MO |
250 | :group 'remember) |
251 | ||
252 | (defvar remember-annotation nil | |
253 | "Current annotation.") | |
254 | (defvar remember-initial-contents nil | |
255 | "Initial contents to place into *Remember* buffer.") | |
174a72ea MO |
256 | |
257 | (defcustom remember-before-remember-hook nil | |
258 | "Functions run before switching to the *Remember* buffer." | |
259 | :type 'hook | |
260 | :group 'remember) | |
15f3eb73 MO |
261 | |
262 | (defcustom remember-run-all-annotation-functions-flag nil | |
7ee68ed5 | 263 | "Non-nil means use all annotations returned by `remember-annotation-functions'." |
15f3eb73 MO |
264 | :type 'boolean |
265 | :group 'remember) | |
266 | ||
267 | ;;;###autoload | |
268 | (defun remember (&optional initial) | |
269 | "Remember an arbitrary piece of data. | |
174a72ea MO |
270 | INITIAL is the text to initially place in the *Remember* buffer, |
271 | or nil to bring up a blank *Remember* buffer. | |
272 | ||
043989e3 | 273 | With a prefix or a visible region, use the region as INITIAL." |
15f3eb73 | 274 | (interactive |
043989e3 MO |
275 | (list (when (or current-prefix-arg |
276 | (and mark-active | |
277 | transient-mark-mode)) | |
278 | (buffer-substring (region-beginning) (region-end))))) | |
15f3eb73 | 279 | (funcall (if remember-in-new-frame |
48c4f9b1 | 280 | #'frameset-to-register |
15f3eb73 MO |
281 | #'window-configuration-to-register) remember-register) |
282 | (let* ((annotation | |
283 | (if remember-run-all-annotation-functions-flag | |
284 | (mapconcat 'identity | |
285 | (delq nil | |
286 | (mapcar 'funcall remember-annotation-functions)) | |
287 | "\n") | |
288 | (run-hook-with-args-until-success | |
289 | 'remember-annotation-functions))) | |
290 | (buf (get-buffer-create remember-buffer))) | |
291 | (run-hooks 'remember-before-remember-hook) | |
292 | (funcall (if remember-in-new-frame | |
293 | #'switch-to-buffer-other-frame | |
294 | #'switch-to-buffer-other-window) buf) | |
295 | (if remember-in-new-frame | |
296 | (set-window-dedicated-p | |
297 | (get-buffer-window (current-buffer) (selected-frame)) t)) | |
29df8a0b | 298 | (setq buffer-offer-save t) |
15f3eb73 MO |
299 | (remember-mode) |
300 | (when (= (point-max) (point-min)) | |
301 | (when initial (insert initial)) | |
302 | (setq remember-annotation annotation) | |
303 | (when remember-initial-contents (insert remember-initial-contents)) | |
304 | (when (and (stringp annotation) | |
305 | (not (equal annotation ""))) | |
306 | (insert "\n\n" annotation)) | |
307 | (setq remember-initial-contents nil) | |
308 | (goto-char (point-min))) | |
309 | (message "Use C-c C-c to remember the data."))) | |
310 | ||
311 | ;;;###autoload | |
312 | (defun remember-other-frame (&optional initial) | |
313 | "Call `remember' in another frame." | |
314 | (interactive | |
315 | (list (when current-prefix-arg | |
316 | (buffer-substring (point) (mark))))) | |
317 | (let ((remember-in-new-frame t)) | |
318 | (remember initial))) | |
319 | ||
15f3eb73 MO |
320 | (defsubst remember-mail-date (&optional rfc822-p) |
321 | "Return a simple date. Nothing fancy." | |
322 | (if rfc822-p | |
323 | (format-time-string "%a, %e %b %Y %T %z" (current-time)) | |
b152c5d3 | 324 | (format-time-string "%a %b %e %T %Y" (current-time)))) |
15f3eb73 MO |
325 | |
326 | (defun remember-buffer-desc () | |
327 | "Using the first line of the current buffer, create a short description." | |
328 | (buffer-substring (point-min) | |
329 | (save-excursion | |
330 | (goto-char (point-min)) | |
331 | (end-of-line) | |
332 | (if (> (- (point) (point-min)) 60) | |
333 | (goto-char (+ (point-min) 60))) | |
334 | (point)))) | |
335 | ||
336 | ;; Remembering to UNIX mailboxes | |
337 | ||
338 | (defcustom remember-mailbox "~/Mail/remember" | |
7ee68ed5 | 339 | "The file in which to store remember data as mail." |
15f3eb73 MO |
340 | :type 'file |
341 | :group 'remember) | |
342 | ||
343 | (defcustom remember-default-priority "medium" | |
7ee68ed5 | 344 | "The default priority for remembered mail messages." |
15f3eb73 MO |
345 | :type 'string |
346 | :group 'remember) | |
347 | ||
348 | (defun remember-store-in-mailbox () | |
349 | "Store remember data as if it were incoming mail. | |
350 | In which case `remember-mailbox' should be the name of the mailbox. | |
7ee68ed5 | 351 | Each piece of pseudo-mail created will have an `X-Todo-Priority' |
15f3eb73 MO |
352 | field, for the purpose of appropriate splitting." |
353 | (let ((who (read-string "Who is this item related to? ")) | |
6f0d4bb6 | 354 | (moment (format "%.0f" (float-time))) |
15f3eb73 MO |
355 | (desc (remember-buffer-desc)) |
356 | (text (buffer-string))) | |
357 | (with-temp-buffer | |
b152c5d3 | 358 | (insert (format "From %s %s |
15f3eb73 MO |
359 | Date: %s |
360 | From: %s | |
361 | Message-Id: <remember-%s@%s> | |
362 | X-Todo-Priority: %s | |
363 | To: %s <%s> | |
364 | Subject: %s\n\n" | |
365 | (user-login-name) | |
366 | (remember-mail-date) | |
367 | (remember-mail-date t) | |
368 | who | |
369 | moment (system-name) | |
370 | remember-default-priority | |
371 | (user-full-name) user-mail-address | |
372 | desc)) | |
373 | (let ((here (point))) | |
374 | (insert text) | |
375 | (unless (bolp) | |
376 | (insert "\n")) | |
377 | (insert "\n") | |
378 | (goto-char here) | |
379 | (while (re-search-forward "^\\(From[: ]\\)" nil t) | |
380 | (replace-match ">\\1"))) | |
381 | (append-to-file (point-min) (point-max) remember-mailbox) | |
382 | t))) | |
383 | ||
15f3eb73 MO |
384 | ;; Remembering to plain files |
385 | ||
940e5099 | 386 | (defcustom remember-data-file (locate-user-emacs-file "notes" ".notes") |
ef099a94 MN |
387 | "The file in which to store unprocessed data. |
388 | When set via customize, visited file of the notes buffer (if it | |
389 | exists) might be changed." | |
ece4bae5 | 390 | :version "24.4" ; added locate-user-emacs-file |
15f3eb73 | 391 | :type 'file |
ef099a94 MN |
392 | :set (lambda (symbol value) |
393 | (let ((buf (find-buffer-visiting (default-value symbol)))) | |
394 | (set-default symbol value) | |
395 | (when (buffer-live-p buf) | |
396 | (with-current-buffer buf | |
397 | (set-visited-file-name | |
398 | (expand-file-name remember-data-file)))))) | |
399 | :initialize 'custom-initialize-default | |
15f3eb73 MO |
400 | :group 'remember) |
401 | ||
402 | (defcustom remember-leader-text "** " | |
7ee68ed5 | 403 | "The text used to begin each remember item." |
15f3eb73 MO |
404 | :type 'string |
405 | :group 'remember) | |
406 | ||
407 | (defun remember-append-to-file () | |
408 | "Remember, with description DESC, the given TEXT." | |
ef099a94 MN |
409 | (let* ((text (buffer-string)) |
410 | (desc (remember-buffer-desc)) | |
411 | (remember-text (concat "\n" remember-leader-text (current-time-string) | |
412 | " (" desc ")\n\n" text | |
413 | (save-excursion (goto-char (point-max)) | |
414 | (if (bolp) nil "\n")))) | |
415 | (buf (find-buffer-visiting remember-data-file))) | |
416 | (if buf | |
417 | (with-current-buffer buf | |
418 | (save-excursion | |
419 | (goto-char (point-max)) | |
420 | (insert remember-text)) | |
421 | (if remember-save-after-remembering (save-buffer))) | |
422 | (append-to-file remember-text nil remember-data-file)))) | |
15f3eb73 | 423 | |
15f3eb73 MO |
424 | (defun remember-region (&optional beg end) |
425 | "Remember the data from BEG to END. | |
174a72ea | 426 | It is called from within the *Remember* buffer to save the text |
043989e3 | 427 | that was entered. |
174a72ea MO |
428 | |
429 | If BEG and END are nil, the entire buffer will be remembered. | |
15f3eb73 | 430 | |
15f3eb73 | 431 | If you want to remember a region, supply a universal prefix to |
7ee68ed5 | 432 | `remember' instead. For example: \\[universal-argument] \\[remember] RET." |
15f3eb73 MO |
433 | ;; Sacha: I have no idea where remember.el gets this context information, but |
434 | ;; you can just use remember-annotation-functions. | |
435 | (interactive) | |
436 | (let ((b (or beg (min (point) (or (mark) (point-min))))) | |
437 | (e (or end (max (point) (or (mark) (point-max)))))) | |
438 | (save-restriction | |
439 | (narrow-to-region b e) | |
440 | (if remember-all-handler-functions | |
441 | (run-hooks 'remember-handler-functions) | |
442 | (run-hook-with-args-until-success 'remember-handler-functions)) | |
443 | (remember-destroy)))) | |
444 | ||
1ffefcf9 | 445 | (defcustom remember-data-directory "~/remember" |
a73fae1f GM |
446 | "The directory in which to store remember data as files. |
447 | Used by `remember-store-in-files'." | |
c034abda BG |
448 | :type 'directory |
449 | :version "24.4" | |
1ffefcf9 BG |
450 | :group 'remember) |
451 | ||
452 | (defcustom remember-directory-file-name-format "%Y-%m-%d_%T-%z" | |
a73fae1f GM |
453 | "Format string for the file name in which to store unprocessed data. |
454 | This is passed to `format-time-string'. | |
455 | Used by `remember-store-in-files'." | |
c034abda BG |
456 | :type 'string |
457 | :version "24.4" | |
1ffefcf9 BG |
458 | :group 'remember) |
459 | ||
460 | (defun remember-store-in-files () | |
461 | "Store remember data in a file in `remember-data-directory'. | |
a73fae1f GM |
462 | The file is named by calling `format-time-string' using |
463 | `remember-directory-file-name-format' as the format string." | |
1ffefcf9 BG |
464 | (let ((name (format-time-string |
465 | remember-directory-file-name-format (current-time))) | |
466 | (text (buffer-string))) | |
467 | (with-temp-buffer | |
468 | (insert text) | |
469 | (write-file (convert-standard-filename | |
470 | (format "%s/%s" remember-data-directory name)))))) | |
471 | ||
15f3eb73 MO |
472 | ;;;###autoload |
473 | (defun remember-clipboard () | |
474 | "Remember the contents of the current clipboard. | |
fb77fe0f | 475 | Most useful for remembering things from other applications." |
15f3eb73 MO |
476 | (interactive) |
477 | (remember (current-kill 0))) | |
478 | ||
174a72ea | 479 | (defun remember-finalize () |
15f3eb73 MO |
480 | "Remember the contents of the current buffer." |
481 | (interactive) | |
482 | (remember-region (point-min) (point-max))) | |
483 | ||
246a4316 | 484 | ;; Org needs this |
cb5b40ee | 485 | (define-obsolete-function-alias 'remember-buffer 'remember-finalize "23.1") |
246a4316 | 486 | |
15f3eb73 MO |
487 | (defun remember-destroy () |
488 | "Destroy the current *Remember* buffer." | |
489 | (interactive) | |
490 | (when (equal remember-buffer (buffer-name)) | |
491 | (kill-buffer (current-buffer)) | |
492 | (jump-to-register remember-register))) | |
493 | ||
3728bf03 MO |
494 | ;;; Diary integration |
495 | ||
496 | (defcustom remember-diary-file nil | |
7ee68ed5 | 497 | "File for extracted diary entries. |
3728bf03 | 498 | If this is nil, then `diary-file' will be used instead." |
a931698a | 499 | :type '(choice (const :tag "diary-file" nil) file) |
3728bf03 MO |
500 | :group 'remember) |
501 | ||
502 | (defun remember-diary-convert-entry (entry) | |
503 | "Translate MSG to an entry readable by diary." | |
504 | (save-match-data | |
505 | (when remember-annotation | |
506 | (setq entry (concat entry " " remember-annotation))) | |
507 | (if (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)" entry) | |
3f651ee6 GM |
508 | (progn |
509 | ;; For calendar-date-style. This costs us nothing because | |
c5de0a17 | 510 | ;; the call to diary-make-entry below loads diary-lib |
3f651ee6 GM |
511 | ;; which requires calendar. |
512 | (require 'calendar) | |
513 | (replace-match | |
514 | (let ((style (if (boundp 'calendar-date-style) | |
515 | calendar-date-style | |
6196cffe | 516 | ;; Don't complain about obsolescence. |
3f651ee6 GM |
517 | (if (with-no-warnings european-calendar-style) |
518 | 'european | |
519 | 'american)))) | |
520 | (cond ((eq style 'european) | |
521 | (concat (match-string 3 entry) "/" | |
522 | (match-string 2 entry) "/" | |
523 | (match-string 1 entry))) | |
524 | ((eq style 'iso) | |
525 | (concat (match-string 1 entry) "-" | |
526 | (match-string 2 entry) "-" | |
527 | (match-string 3 entry))) | |
528 | (t (concat (match-string 2 entry) "/" | |
529 | (match-string 3 entry) "/" | |
530 | (match-string 1 entry))))) | |
531 | t t entry)) | |
3728bf03 MO |
532 | entry))) |
533 | ||
c5de0a17 | 534 | (autoload 'diary-make-entry "diary-lib") |
3728bf03 MO |
535 | |
536 | ;;;###autoload | |
537 | (defun remember-diary-extract-entries () | |
538 | "Extract diary entries from the region." | |
539 | (save-excursion | |
540 | (goto-char (point-min)) | |
541 | (let (list) | |
542 | (while (re-search-forward "^DIARY:\\s-*\\(.+\\)" nil t) | |
c6dab55f | 543 | (push (remember-diary-convert-entry (match-string 1)) list)) |
3728bf03 | 544 | (when list |
800aaa89 | 545 | (diary-make-entry (mapconcat 'identity list "\n") |
612b0592 | 546 | nil remember-diary-file)) |
3728bf03 MO |
547 | nil))) ;; Continue processing |
548 | ||
15f3eb73 MO |
549 | ;;; Internal Functions: |
550 | ||
80f0c18f MO |
551 | (defvar remember-mode-map |
552 | (let ((map (make-sparse-keymap))) | |
553 | (define-key map "\C-x\C-s" 'remember-finalize) | |
554 | (define-key map "\C-c\C-c" 'remember-finalize) | |
869dc290 | 555 | (define-key map "\C-c\C-k" 'remember-destroy) |
869dc290 | 556 | map) |
95160c90 | 557 | "Keymap used in `remember-mode'.") |
15f3eb73 | 558 | |
7ee68ed5 | 559 | (define-derived-mode remember-mode indented-text-mode "Remember" |
15f3eb73 | 560 | "Major mode for output from \\[remember]. |
869dc290 | 561 | This buffer is used to collect data that you want to remember. |
7ee68ed5 JB |
562 | \\<remember-mode-map> |
563 | Just hit \\[remember-finalize] when you're done entering, and it will file | |
869dc290 MO |
564 | the data away for latter retrieval, and possible indexing. |
565 | ||
566 | \\{remember-mode-map}" | |
7ee68ed5 | 567 | (set-keymap-parent remember-mode-map nil)) |
15f3eb73 | 568 | |
ef099a94 MN |
569 | ;; Notes buffer showing the notes: |
570 | ||
571 | (defcustom remember-notes-buffer-name "*notes*" | |
572 | "Name of the notes buffer. | |
573 | Setting it to *scratch* will hijack the *scratch* buffer for the | |
574 | purpose of storing notes." | |
575 | :type 'string | |
576 | :version "24.4") | |
577 | ||
578 | (defcustom remember-notes-initial-major-mode nil | |
a73fae1f GM |
579 | "Major mode to use in the notes buffer when it's created. |
580 | If this is nil, use `initial-major-mode'." | |
581 | :type '(choice (const :tag "Use `initial-major-mode'" nil) | |
ef099a94 MN |
582 | (function :tag "Major mode" text-mode)) |
583 | :version "24.4") | |
584 | ||
585 | (defcustom remember-notes-bury-on-kill t | |
a73fae1f | 586 | "Non-nil means `kill-buffer' will bury the notes buffer instead of killing." |
ef099a94 MN |
587 | :type 'boolean |
588 | :version "24.4") | |
589 | ||
590 | (defun remember-notes-save-and-bury-buffer () | |
a73fae1f | 591 | "Save (if it is modified) and bury the current buffer." |
ef099a94 MN |
592 | (interactive) |
593 | (when (buffer-modified-p) | |
594 | (save-buffer)) | |
595 | (bury-buffer)) | |
596 | ||
597 | ||
598 | ||
599 | (defvar remember-notes-mode-map | |
600 | (let ((map (make-sparse-keymap))) | |
601 | (define-key map "\C-c\C-c" 'remember-notes-save-and-bury-buffer) | |
602 | map) | |
95160c90 | 603 | "Keymap used in `remember-notes-mode'.") |
ef099a94 MN |
604 | |
605 | (define-minor-mode remember-notes-mode | |
95160c90 GM |
606 | "Minor mode for the `remember-notes' buffer. |
607 | This sets `buffer-save-without-query' so that `save-some-buffers' will | |
608 | save the notes buffer without asking. | |
609 | ||
610 | \\{remember-notes-mode-map}" | |
ef099a94 MN |
611 | nil nil nil |
612 | (cond | |
613 | (remember-notes-mode | |
614 | (add-hook 'kill-buffer-query-functions | |
615 | #'remember-notes--kill-buffer-query nil t) | |
616 | (setq buffer-save-without-query t)))) | |
617 | ||
618 | ;;;###autoload | |
619 | (defun remember-notes (&optional switch-to) | |
95160c90 GM |
620 | "Return the notes buffer, creating it if needed, and maybe switch to it. |
621 | This buffer is for notes that you want to preserve across Emacs sessions. | |
622 | The notes are saved in `remember-data-file'. | |
623 | ||
624 | If a buffer is already visiting that file, just return it. | |
625 | ||
626 | Otherwise, create the buffer, and rename it to `remember-notes-buffer-name', | |
627 | unless a buffer of that name already exists. Set the major mode according | |
628 | to `remember-notes-initial-major-mode', and enable `remember-notes-mode' | |
629 | minor mode. | |
630 | ||
631 | Use \\<remember-notes-mode-map>\\[remember-notes-save-and-bury-buffer] to save and bury the notes buffer. | |
632 | ||
633 | Interactively, or if SWITCH-TO is non-nil, switch to the buffer. | |
634 | Return the buffer. | |
635 | ||
636 | Set `initial-buffer-choice' to `remember-notes' to visit your notes buffer | |
637 | when Emacs starts. Set `remember-notes-buffer-name' to \"*scratch*\" | |
638 | to turn the *scratch* buffer into your notes buffer." | |
ef099a94 MN |
639 | (interactive "p") |
640 | (let ((buf (or (find-buffer-visiting remember-data-file) | |
641 | (with-current-buffer (find-file-noselect remember-data-file) | |
642 | (and remember-notes-buffer-name | |
643 | (not (get-buffer remember-notes-buffer-name)) | |
644 | (rename-buffer remember-notes-buffer-name)) | |
645 | (funcall (or remember-notes-initial-major-mode | |
646 | initial-major-mode)) | |
647 | (remember-notes-mode 1) | |
648 | (current-buffer))))) | |
649 | (when switch-to | |
650 | (switch-to-buffer buf)) | |
651 | buf)) | |
652 | ||
653 | (defun remember-notes--kill-buffer-query () | |
a73fae1f GM |
654 | "Function that `remember-notes-mode' adds to `kill-buffer-query-functions'. |
655 | Save the current buffer if modified. If `remember-notes-bury-on-kill' | |
656 | is non-nil, bury it and return nil; otherwise return t." | |
ef099a94 MN |
657 | (when (buffer-modified-p) |
658 | (save-buffer)) | |
659 | (if remember-notes-bury-on-kill | |
a73fae1f GM |
660 | (progn |
661 | ;; bury-buffer always returns nil, but let's be explicit. | |
662 | (bury-buffer) | |
663 | nil) | |
ef099a94 MN |
664 | t)) |
665 | ||
95160c90 GM |
666 | (provide 'remember) |
667 | ||
15f3eb73 | 668 | ;;; remember.el ends here |