comparison lisp/textmodes/remember.el @ 85772:6b9c41aaadf8

Check in Remember Mode
author Michael Olson <mwolson@gnu.org>
date Tue, 30 Oct 2007 01:39:14 +0000
parents
children 5810ee84e0f9
comparison
equal deleted inserted replaced
85771:a7aa5ee6bc3a 85772:6b9c41aaadf8
1 ;;; remember --- a mode for quickly jotting down things to remember
2
3 ;; Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006,
4 ;; 2007 Free Software Foundation, Inc.
5
6 ;; Author: John Wiegley <johnw@gnu.org>
7 ;; Created: 29 Mar 1999
8 ;; Version: 1.9
9 ;; Keywords: data memory todo pim
10 ;; URL: http://gna.org/projects/remember-el/
11
12 ;; This file is part of GNU Emacs.
13
14 ;; GNU Emacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 3, or (at your option)
17 ;; any later version.
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
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
28
29 ;;; Commentary:
30
31 ;; The idea
32 ;;
33 ;; Todo lists, schedules, phone databases... everything we use
34 ;; databases for is really just a way to extend the power of our
35 ;; memory. To be able to remember what our conscious mind may not
36 ;; currently have access to.
37 ;;
38 ;; There are many different databases out there -- and good ones --
39 ;; which this mode is not trying to replace. Rather, it's how that
40 ;; data gets there that's the question. Most of the time, we just
41 ;; want to say "Remember so-and-so's phone number, or that I have to
42 ;; buy dinner for the cats tonight." That's the FACT. How it's
43 ;; stored is really the computer's problem. But at this point in
44 ;; time, it's most definitely also the user's problem, and sometimes
45 ;; so laboriously so that people just let data slip, rather than
46 ;; expend the effort to record it.
47 ;;
48 ;; "Remember" is a mode for remembering data. It uses whatever
49 ;; back-end is appropriate to record and correlate the data, but it's
50 ;; main intention is to allow you to express as _little_ structure as
51 ;; possible up front. If you later want to express more powerful
52 ;; relationships between your data, or state assumptions that were at
53 ;; first too implicit to be recognized, you can "study" the data later
54 ;; and rearrange it. But the initial "just remember this" impulse
55 ;; should be as close to simply throwing the data at Emacs as
56 ;; possible.
57 ;;
58 ;; Implementation
59 ;;
60 ;; Hyperbole, as a data presentation tool, always struck me as being
61 ;; very powerful, but it seemed to require a lot of "front-end" work
62 ;; before that data was really available. The problem with BBDB, or
63 ;; keeping up a Bibl-mode file, is that you have to use different
64 ;; functions to record the data, and it always takes time to stop what
65 ;; you're doing, format the data in the manner expected by that
66 ;; particular data interface, and then resume your work.
67 ;;
68 ;; With "remember", you just hit `M-x remember' (you'd probably want
69 ;; to bind this to an easily accessible keystroke, like C-x M-r), slam
70 ;; in your text however you like, and then hit C-c C-c. It will file
71 ;; the data away for later retrieval, and possibly indexing.
72 ;;
73 ;; Indexing is to data what "studying" is in the real world. What you
74 ;; do when you study (or lucubrate, for some of us) is to realize
75 ;; certain relationships implicit in the data, so that you can make
76 ;; use of those relationships. Expressing that a certain quote you
77 ;; remembered was a religious quote, and that you want the ability to
78 ;; pull up all quotes of a religious nature, is what studying does.
79 ;; This is a more labor intensive task than the original remembering
80 ;; of the data, and it's typical in real life to set aside a special
81 ;; period of time for doing this work.
82 ;;
83 ;; "Remember" works in the same way. When you enter data, either by
84 ;; typing it into a buffer, or using the contents of the selected
85 ;; region, it will store that data -- unindexed, uninterpreted -- in a
86 ;; data pool. It will also try to remember as much context
87 ;; information as possible (any text properties that were set, where
88 ;; you copied it from, when, how, etc). Later, you can walk through
89 ;; your accumulated set of data (both organized, and unorganized) and
90 ;; easily begin moving things around, and making annotations that will
91 ;; express the full meaning of that data, as far as you know it.
92 ;;
93 ;; Obviously this latter stage is more user-interface intensive, and
94 ;; it would be nice if "remember" could do it as elegantly as
95 ;; possible, rather than requiring a billion keystrokes to reorganize
96 ;; your hierarchy. Well, as the future arrives, hopefully experience
97 ;; and user feedback will help to make this as intuitive a tool as
98 ;; possible.
99 ;;
100 ;; Future Goals
101 ;;
102 ;; This tool hopes to track (and by doing it with as little new code
103 ;; as possible):
104 ;;
105 ;; - The raw data that gets entered
106 ;;
107 ;; - The relationships between that data (either determined
108 ;; implicitly by parsing the input, or explicitly by the user's
109 ;; studying the data).
110 ;;
111 ;; - Revisioning of the data
112 ;;
113 ;; - Where it came from, and any context information that can be
114 ;; programmatically determined.
115 ;;
116 ;; - Allowing particular views of the initially amorphous data pool
117 ;; (ala the Xanadu concept).
118 ;;
119 ;; - Storage of the data in a manner most appopriate to that data,
120 ;; such as keeping address-book type information in BBDB, etc.
121 ;;
122 ;; Using "remember"
123 ;;
124 ;; As a rough beginning, what I do is to keep my .notes file in
125 ;; outline-mode format, with a final entry called "* Raw data". Then,
126 ;; at intervals, I can move the data that gets appended there into
127 ;; other places. But certainly this should evolve into an intuitive
128 ;; mechanism for shuffling data off to its appropriate corner of the
129 ;; universe.
130 ;;
131 ;; Mapping the remember functions to very accessible keystrokes
132 ;; facilities using the mode:
133 ;;
134 ;; (autoload 'remember "remember" nil t)
135 ;; (autoload 'remember-region "remember" nil t)
136 ;;
137 ;; (define-key global-map [f8] 'remember)
138 ;; (define-key global-map [f9] 'remember-region)
139 ;;
140 ;; planner.el users should use `remember-to-planner' instead of `remember'
141 ;; to save more context information.
142 ;;
143 ;; Feedback
144 ;;
145 ;; If Emacs could become a more intelligent data store, where
146 ;; brainstorming would focus on the IDEAS involved -- rather than the
147 ;; structuring and format of those ideas, or having to stop your
148 ;; current flow of work in order to record them -- it would map much
149 ;; more closely to how the mind (well, at least mine) works, and hence
150 ;; would eliminate that very manual-ness which computers from the very
151 ;; beginning have been championed as being able to reduce.
152 ;;
153 ;; Have you ever noticed that having a laptop to write on doesn't
154 ;; _actually_ increase the amount of quality material that you turn
155 ;; out, in the long run? Perhaps its because the time we save
156 ;; electronically in one way, we're losing electronically in another;
157 ;; the tool should never dominate one's focus. As the mystic
158 ;; Faridu'd-Din `Attar wrote: "Be occupied as little as possible with
159 ;; things of the outer world but much with things of the inner world;
160 ;; then right action will overcome inaction."
161
162 ;;; History:
163
164 ;;; Code:
165
166 (provide 'remember)
167
168 (defconst remember-version "1.9"
169 "This version of remember.")
170
171 (defgroup remember nil
172 "A mode to remember information."
173 :group 'data)
174
175 ;;; User Variables:
176
177 (defcustom remember-mode-hook nil
178 "Functions run upon entering `remember-mode'."
179 :type 'hook
180 :options '(flyspell-mode turn-on-auto-fill)
181 :group 'remember)
182
183 (defcustom remember-in-new-frame nil
184 "Non-nil means use a separate frame for capturing remember data."
185 :type 'boolean
186 :group 'remember)
187
188 (defcustom remember-register ?R
189 "The register in which the window configuration is stored."
190 :type 'character
191 :group 'remember)
192
193 (defcustom remember-filter-functions nil
194 "*Functions run to filter remember data.
195 All functions are run in the remember buffer."
196 :type 'hook
197 :group 'remember)
198
199 (defcustom remember-handler-functions '(remember-append-to-file)
200 "*Functions run to process remember data.
201 Each function is called with the current buffer narrowed to what the
202 user wants remembered.
203 If any function returns non-nil, the data is assumed to have been
204 recorded somewhere by that function. "
205 :type 'hook
206 :group 'remember)
207
208 (defcustom remember-all-handler-functions nil
209 "If non-nil every function in `remember-handler-functions' is
210 called."
211 :type 'boolean
212 :group 'remember)
213
214 ;;; Internal Variables:
215
216 (defvar remember-buffer "*Remember*"
217 "The name of the remember data entry buffer.")
218
219 (defcustom remember-save-after-remembering t
220 "*Non-nil means automatically save after remembering."
221 :type 'boolean
222 :group 'remember)
223
224 ;;; User Functions:
225
226 ;; People with planner.el can set this to planner-annotation-functions:
227 ;; (defvaralias 'remember-annotation-functions 'planner-annotation-functions)
228 ;; or (defalias 'remember-annotation-functions 'planner-annotation-functions)
229 (defcustom remember-annotation-functions
230 (if (boundp 'planner-annotation-functions)
231 planner-annotation-functions
232 '(buffer-file-name))
233 "Hook that returns an annotation to be inserted into the remember buffer.
234 If you have planner.el, it's nice to set this to
235 `planner-annotation-functions'."
236 :type 'hook
237 :group 'remember)
238
239 (defvar remember-annotation nil
240 "Current annotation.")
241 (defvar remember-initial-contents nil
242 "Initial contents to place into *Remember* buffer.")
243 (defvar remember-before-remember-hook nil
244 "Functions run before switching to the *Remember* buffer.")
245
246 (defcustom remember-run-all-annotation-functions-flag nil
247 "Non-nil means use all annotations returned by
248 `remember-annotation-functions'."
249 :type 'boolean
250 :group 'remember)
251
252 ;;;###autoload
253 (defun remember (&optional initial)
254 "Remember an arbitrary piece of data.
255 With a prefix, uses the region as INITIAL."
256 (interactive
257 (list (when current-prefix-arg
258 (buffer-substring (point) (mark)))))
259 (funcall (if remember-in-new-frame
260 #'frame-configuration-to-register
261 #'window-configuration-to-register) remember-register)
262 (let* ((annotation
263 (if remember-run-all-annotation-functions-flag
264 (mapconcat 'identity
265 (delq nil
266 (mapcar 'funcall remember-annotation-functions))
267 "\n")
268 (run-hook-with-args-until-success
269 'remember-annotation-functions)))
270 (buf (get-buffer-create remember-buffer)))
271 (run-hooks 'remember-before-remember-hook)
272 (funcall (if remember-in-new-frame
273 #'switch-to-buffer-other-frame
274 #'switch-to-buffer-other-window) buf)
275 (if remember-in-new-frame
276 (set-window-dedicated-p
277 (get-buffer-window (current-buffer) (selected-frame)) t))
278 (remember-mode)
279 (when (= (point-max) (point-min))
280 (when initial (insert initial))
281 (setq remember-annotation annotation)
282 (when remember-initial-contents (insert remember-initial-contents))
283 (when (and (stringp annotation)
284 (not (equal annotation "")))
285 (insert "\n\n" annotation))
286 (setq remember-initial-contents nil)
287 (goto-char (point-min)))
288 (message "Use C-c C-c to remember the data.")))
289
290 ;;;###autoload
291 (defun remember-other-frame (&optional initial)
292 "Call `remember' in another frame."
293 (interactive
294 (list (when current-prefix-arg
295 (buffer-substring (point) (mark)))))
296 (let ((remember-in-new-frame t))
297 (remember initial)))
298
299 (defsubst remember-time-to-seconds (time)
300 "Convert TIME to a floating point number."
301 (+ (* (car time) 65536.0)
302 (cadr time)
303 (/ (or (car (cdr (cdr time))) 0) 1000000.0)))
304
305 (defsubst remember-mail-date (&optional rfc822-p)
306 "Return a simple date. Nothing fancy."
307 (if rfc822-p
308 (format-time-string "%a, %e %b %Y %T %z" (current-time))
309 (format-time-string "%c" (current-time))))
310
311 (defun remember-buffer-desc ()
312 "Using the first line of the current buffer, create a short description."
313 (buffer-substring (point-min)
314 (save-excursion
315 (goto-char (point-min))
316 (end-of-line)
317 (if (> (- (point) (point-min)) 60)
318 (goto-char (+ (point-min) 60)))
319 (point))))
320
321 ;; Remembering to UNIX mailboxes
322
323 (defcustom remember-mailbox "~/Mail/remember"
324 "*The file in which to store remember data as mail."
325 :type 'file
326 :group 'remember)
327
328 (defcustom remember-default-priority "medium"
329 "*The default priority for remembered mail messages."
330 :type 'string
331 :group 'remember)
332
333 (defun remember-store-in-mailbox ()
334 "Store remember data as if it were incoming mail.
335 In which case `remember-mailbox' should be the name of the mailbox.
336 Each piece of psuedo-mail created will have an `X-Todo-Priority'
337 field, for the purpose of appropriate splitting."
338 (let ((who (read-string "Who is this item related to? "))
339 (moment
340 (format "%.0f" (remember-time-to-seconds (current-time))))
341 (desc (remember-buffer-desc))
342 (text (buffer-string)))
343 (with-temp-buffer
344 (insert (format "
345 From %s %s
346 Date: %s
347 From: %s
348 Message-Id: <remember-%s@%s>
349 X-Todo-Priority: %s
350 To: %s <%s>
351 Subject: %s\n\n"
352 (user-login-name)
353 (remember-mail-date)
354 (remember-mail-date t)
355 who
356 moment (system-name)
357 remember-default-priority
358 (user-full-name) user-mail-address
359 desc))
360 (let ((here (point)))
361 (insert text)
362 (unless (bolp)
363 (insert "\n"))
364 (insert "\n")
365 (goto-char here)
366 (while (re-search-forward "^\\(From[: ]\\)" nil t)
367 (replace-match ">\\1")))
368 (append-to-file (point-min) (point-max) remember-mailbox)
369 t)))
370
371 (custom-add-option 'remember-handler-functions 'remember-store-in-mailbox)
372
373 ;; Remembering to plain files
374
375 (defcustom remember-data-file "~/.notes"
376 "*The file in which to store unprocessed data."
377 :type 'file
378 :group 'remember)
379
380 (defcustom remember-leader-text "** "
381 "*The text used to begin each remember item."
382 :type 'string
383 :group 'remember)
384
385 (defun remember-append-to-file ()
386 "Remember, with description DESC, the given TEXT."
387 (let ((text (buffer-string))
388 (desc (remember-buffer-desc)))
389 (with-temp-buffer
390 (insert "\n" remember-leader-text (current-time-string)
391 " (" desc ")\n\n" text)
392 (if (not (bolp))
393 (insert "\n"))
394 (if (find-buffer-visiting remember-data-file)
395 (let ((remember-text (buffer-string)))
396 (set-buffer (get-file-buffer remember-data-file))
397 (save-excursion
398 (goto-char (point-max))
399 (insert remember-text)
400 (when remember-save-after-remembering (save-buffer))))
401 (append-to-file (point-min) (point-max) remember-data-file)))))
402
403 (custom-add-option 'remember-handler-functions 'remember-append-to-file)
404
405 ;;;###autoload
406 (defun remember-region (&optional beg end)
407 "Remember the data from BEG to END.
408 If called from within the remember buffer, BEG and END are ignored,
409 and the entire buffer will be remembered.
410
411 This function is meant to be called from the *Remember* buffer.
412 If you want to remember a region, supply a universal prefix to
413 `remember' instead. For example: C-u M-x remember."
414 ;; Sacha: I have no idea where remember.el gets this context information, but
415 ;; you can just use remember-annotation-functions.
416 (interactive)
417 (let ((b (or beg (min (point) (or (mark) (point-min)))))
418 (e (or end (max (point) (or (mark) (point-max))))))
419 (save-restriction
420 (narrow-to-region b e)
421 (if remember-all-handler-functions
422 (run-hooks 'remember-handler-functions)
423 (run-hook-with-args-until-success 'remember-handler-functions))
424 (remember-destroy))))
425
426 ;;;###autoload
427 (defun remember-clipboard ()
428 "Remember the contents of the current clipboard.
429 Most useful for remembering things from Netscape or other X Windows
430 application."
431 (interactive)
432 (remember (current-kill 0)))
433
434 ;;;###autoload
435 (defun remember-buffer ()
436 "Remember the contents of the current buffer."
437 (interactive)
438 (remember-region (point-min) (point-max)))
439
440 ;;;###autoload
441 (defun remember-destroy ()
442 "Destroy the current *Remember* buffer."
443 (interactive)
444 (when (equal remember-buffer (buffer-name))
445 (kill-buffer (current-buffer))
446 (jump-to-register remember-register)))
447
448 ;;; Internal Functions:
449
450 (defvar remember-mode-map ()
451 "Keymap used in Remember mode.")
452 (when (not remember-mode-map)
453 (setq remember-mode-map (make-sparse-keymap))
454 (define-key remember-mode-map "\C-x\C-s" 'remember-buffer)
455 (define-key remember-mode-map "\C-c\C-c" 'remember-buffer)
456 (define-key remember-mode-map "\C-c\C-k" 'remember-destroy))
457
458 (defun remember-mode ()
459 "Major mode for output from \\[remember].
460 \\<remember-mode-map>This buffer is used to collect data that you want
461 remember. Just hit \\[remember-region] when you're done entering, and
462 it will go ahead and file the data for latter retrieval, and possible
463 indexing. \\{remember-mode-map}"
464 (interactive)
465 (kill-all-local-variables)
466 (indented-text-mode)
467 (use-local-map remember-mode-map)
468 (setq major-mode 'remember-mode
469 mode-name "Remember")
470 (run-hooks 'remember-mode-hook))
471
472 ;;; remember.el ends here