Commit | Line | Data |
---|---|---|
01b864bc | 1 | ;; todo-mode.el -- Major mode for editing TODO list files |
3cb152f9 | 2 | |
a554b301 | 3 | ;; Copyright (C) 1997, 2000 Free Software Foundation, Inc. |
3cb152f9 | 4 | |
89802f43 | 5 | ;; Author: os10000@seidel-space.de [not clear that this works, July 2000] |
7c896f63 | 6 | ;; Created: 2 Aug 1997 |
89802f43 | 7 | ;; Version: $Id: todo-mode.el,v 1.41 2000/06/06 16:43:40 fx Exp $ |
7c896f63 | 8 | ;; Keywords: Categorised TODO list editor, todo-mode |
3cb152f9 | 9 | |
7c896f63 | 10 | ;; This file is part of GNU Emacs. |
595b2334 | 11 | |
7c896f63 | 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
595b2334 OS |
13 | ;; it under the terms of the GNU General Public License as published by |
14 | ;; the Free Software Foundation; either version 2, or (at your option) | |
15 | ;; any later version. | |
7c896f63 OS |
16 | |
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
595b2334 OS |
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. | |
7c896f63 | 21 | |
595b2334 OS |
22 | ;; You should have received a copy of the GNU General Public License |
23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
24 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
25 | ;; Boston, MA 02111-1307, USA. | |
26 | ||
27 | ;; --------------------------------------------------------------------------- | |
28 | ||
7c896f63 OS |
29 | ;;; Commentary: |
30 | ||
85b3b166 OS |
31 | ;; Mode Description |
32 | ;; | |
33 | ;; TODO is a major mode for EMACS which offers functionality to | |
34 | ;; treat most lines in one buffer as a list of items one has to | |
35 | ;; do. There are facilities to add new items, which are | |
36 | ;; categorised, to edit or even delete items from the buffer. | |
37 | ;; The buffer contents are currently compatible with the diary, | |
38 | ;; so that the list of todo-items will show up in the FANCY diary | |
39 | ;; mode. | |
40 | ;; | |
41 | ;; Notice: Besides the major mode, this file also exports the | |
42 | ;; function `todo-show' which will change to the one specific | |
43 | ;; TODO file that has been specified in the todo-file-do | |
44 | ;; variable. If this file does not conform to the TODO mode | |
45 | ;; conventions, the todo-show function will add the appropriate | |
46 | ;; header and footer. I don't anticipate this to cause much | |
47 | ;; grief, but be warned, in case you attempt to read a plain text | |
48 | ;; file. | |
49 | ;; | |
01b864bc | 50 | ;; Preface, Quickstart Installation |
595b2334 | 51 | ;; |
e4541b67 | 52 | ;; To get this to work, make emacs execute the line |
3d8105fb | 53 | ;; |
e4541b67 | 54 | ;; (autoload 'todo-mode "todo-mode" |
4cbc9d5a OS |
55 | ;; "Major mode for editing TODO lists." t) |
56 | ;; (autoload 'todo-show "todo-mode" | |
57 | ;; "Show TODO items." t) | |
58 | ;; (autoload 'todo-insert-item "todo-mode" | |
59 | ;; "Add TODO item." t) | |
7c896f63 | 60 | ;; |
e4541b67 OS |
61 | ;; You may now enter new items by typing "M-x todo-insert-item", |
62 | ;; or enter your TODO list file by typing "M-x todo-show". | |
63 | ;; | |
dad8ca4c OS |
64 | ;; ------------------------------------------------------------- |
65 | ;; | |
66 | ;; oh no, it doesn't work any more ... but Alex Schroeder | |
67 | ;; <a.schroeder@bsiag.ch> writes: | |
68 | ;; | |
69 | ;; ------------------------------------------------------------- | |
70 | ;; | |
71 | ;; 1. Call todo-show (I called todo-insert first) | |
72 | ;; 2. Add some categories (I called todo-insert) | |
73 | ;; 3. Save the buffer, restart Emacs (perhaps restarting Emacs is not | |
74 | ;; required) | |
75 | ;; 4. Only now can you start to add entries. | |
76 | ;; | |
77 | ;; This is a bit cumbersome, and it should be documented. You probably | |
78 | ;; | |
79 | ;; ------------------------------------------------------------- | |
80 | ;; | |
81 | ;; and right he is. My apologies, I'll try to fix it sometime. | |
82 | ;; | |
83 | ;; ------------------------------------------------------------- | |
84 | ;; | |
e4541b67 OS |
85 | ;; The TODO list file has a special format and some auxiliary |
86 | ;; information, which will be added by the todo-show function if | |
87 | ;; it attempts to visit an un-initialised file. Hence it is | |
88 | ;; recommended to use the todo-show function for the first time, | |
89 | ;; in order to initialise the file, but it is not necessary | |
90 | ;; afterwards. | |
91 | ;; | |
92 | ;; As these commands are quite long to type, I would recommend | |
93 | ;; the addition of two bindings to your to your global keymap. I | |
94 | ;; personally have the following in my initialisation file: | |
95 | ;; | |
96 | ;; (global-set-key "\C-ct" 'todo-show) ;; switch to TODO buffer | |
01b864bc | 97 | ;; (global-set-key "\C-ci" 'todo-insert-item) ;; insert new item |
7c896f63 | 98 | ;; |
e4541b67 OS |
99 | ;; Note, however, that this recommendation has prompted some |
100 | ;; criticism, since the keys C-c LETTER are reserved for user | |
101 | ;; functions. I believe my recommendation is acceptable, since | |
102 | ;; the Emacs Lisp Manual *Tips* section also details that the | |
103 | ;; mode itself should not bind any functions to those keys. The | |
104 | ;; express aim of the above two bindings is to work outside the | |
105 | ;; mode, which doesn't need the show function and offers a | |
106 | ;; different binding for the insert function. They serve as | |
107 | ;; shortcuts and are not even needed (since the TODO mode will be | |
108 | ;; entered by visiting the TODO file, and later by switching to | |
109 | ;; its buffer). | |
110 | ;; | |
5d035cad OS |
111 | ;; If you are an advanced user of this package, please consult |
112 | ;; the whole source code for autoloads, because there are several | |
113 | ;; extensions that are not explicitly listed in the above quick | |
114 | ;; installation. | |
115 | ;; | |
e4541b67 | 116 | ;; Version |
7c896f63 | 117 | ;; |
e4541b67 | 118 | ;; Which version of todo-mode.el does this documentation refer to? |
579e1c67 | 119 | ;; |
89802f43 | 120 | ;; $Id: todo-mode.el,v 1.41 2000/06/06 16:43:40 fx Exp $ |
01b864bc | 121 | ;; |
e4541b67 | 122 | ;; Operation |
01b864bc OS |
123 | ;; |
124 | ;; You will have the following facilities available: | |
125 | ;; | |
126 | ;; M-x todo-show will enter the todo list screen, here type | |
127 | ;; | |
bd40f1f2 OS |
128 | ;; spc will toggle the display of sub-trees |
129 | ;; | |
01b864bc OS |
130 | ;; + to go to next category |
131 | ;; - to go to previous category | |
e4541b67 OS |
132 | ;; d to file the current entry, including a |
133 | ;; comment and timestamp | |
01b864bc | 134 | ;; e to edit the current entry |
1966902e | 135 | ;; E to edit a multi-line entry |
01b864bc OS |
136 | ;; f to file the current entry, including a |
137 | ;; comment and timestamp | |
4dc1a160 | 138 | ;; i to insert a new entry, with prefix, omit category |
1966902e | 139 | ;; I to insert a new entry at current cursor position |
e4541b67 | 140 | ;; j jump to category |
01b864bc OS |
141 | ;; k to kill the current entry |
142 | ;; l to lower the current entry's priority | |
143 | ;; n for the next entry | |
144 | ;; p for the previous entry | |
e4541b67 | 145 | ;; P print |
01b864bc OS |
146 | ;; q to save the list and exit the buffer |
147 | ;; r to raise the current entry's priority | |
148 | ;; s to save the list | |
f1757bdd | 149 | ;; S to save the list of top priorities |
85b3b166 | 150 | ;; t show top priority items for each category |
01b864bc | 151 | ;; |
e4541b67 OS |
152 | ;; When you add a new entry, you are asked for the text and then |
153 | ;; for the category. I for example have categories for things | |
154 | ;; that I want to do in the office (like mail my mum), that I | |
155 | ;; want to do in town (like buy cornflakes) and things I want to | |
156 | ;; do at home (move my suitcases). The categories can be | |
157 | ;; selected with the cursor keys and if you type in the name of a | |
158 | ;; category which didn't exist before, an empty category of the | |
159 | ;; desired name will be added and filled with the new entry. | |
01b864bc OS |
160 | ;; |
161 | ;; Configuration | |
162 | ;; | |
163 | ;; Variable todo-prefix | |
164 | ;; | |
165 | ;; I would like to recommend that you use the prefix "*/*" (by | |
e4541b67 OS |
166 | ;; leaving the variable 'todo-prefix' untouched) so that the |
167 | ;; diary displays each entry every day. | |
01b864bc | 168 | ;; |
e4541b67 OS |
169 | ;; To understand what I mean, please read the documentation that |
170 | ;; goes with the calendar since that will tell you how you can | |
171 | ;; set up the fancy diary display and use the #include command to | |
172 | ;; include your todo list file as part of your diary. | |
01b864bc | 173 | ;; |
e4541b67 OS |
174 | ;; If you have the diary package set up to usually display more |
175 | ;; than one day's entries at once, consider using | |
01b864bc OS |
176 | ;; |
177 | ;; "&%%(equal (calendar-current-date) date)" | |
178 | ;; | |
e4541b67 OS |
179 | ;; as the value of `todo-prefix'. Please note that this may slow |
180 | ;; down the processing of your diary file some. | |
01b864bc | 181 | ;; |
5d035cad OS |
182 | ;; Carsten Dominik <dominik@strw.LeidenUniv.nl> suggested that |
183 | ;; | |
184 | ;; "&%%(todo-cp)" | |
185 | ;; | |
186 | ;; might be nicer and to that effect a function has been declared | |
187 | ;; further down in the code. You may wish to auto-load this. | |
188 | ;; | |
189 | ;; Carsten also writes that that *changing* the prefix after the | |
190 | ;; todo list is already established is not as simple as changing | |
191 | ;; the variable - the todo files have to be changed by hand. | |
192 | ;; | |
01b864bc OS |
193 | ;; Variable todo-file-do |
194 | ;; | |
e4541b67 OS |
195 | ;; This variable is fairly self-explanatory. You have to store |
196 | ;; your TODO list somewhere. This variable tells the package | |
197 | ;; where to go and find this file. | |
01b864bc OS |
198 | ;; |
199 | ;; Variable todo-file-done | |
200 | ;; | |
e4541b67 OS |
201 | ;; Even when you're done, you may wish to retain the entries. |
202 | ;; Given that they're timestamped and you are offered to add a | |
203 | ;; comment, this can make a useful diary of past events. It will | |
204 | ;; even blend in with the EMACS diary package. So anyway, this | |
205 | ;; variable holds the name of the file for the filed todo-items. | |
01b864bc | 206 | ;; |
f1757bdd OS |
207 | ;; Variable todo-file-top |
208 | ;; | |
209 | ;; File storing the top priorities of your TODO list when | |
210 | ;; todo-save-top-priorities is non-nil. Nice to include in your | |
211 | ;; diary instead of the complete TODO list. | |
212 | ;; | |
01b864bc OS |
213 | ;; Variable todo-mode-hook |
214 | ;; | |
e4541b67 OS |
215 | ;; Just like other modes, too, this mode offers to call your |
216 | ;; functions before it goes about its business. This variable | |
217 | ;; will be inspected for any functions you may wish to have | |
218 | ;; called once the other TODO mode preparations have been | |
219 | ;; completed. | |
220 | ;; | |
221 | ;; Variable todo-insert-threshold | |
222 | ;; | |
223 | ;; Another nifty feature is the insertion accuracy. If you have | |
224 | ;; 8 items in your TODO list, then you may get asked 4 questions | |
225 | ;; by the binary insertion algorithm. However, you may not | |
226 | ;; really have a need for such accurate priorities amongst your | |
227 | ;; TODO items. If you now think about the binary insertion | |
228 | ;; halfing the size of the window each time, then the threshhold | |
229 | ;; is the window size at which it will stop. If you set the | |
230 | ;; threshhold to zero, the upper and lower bound will coincide at | |
231 | ;; the end of the loop and you will insert your item just before | |
85b3b166 | 232 | ;; that point. If you set the threshhold to, e.g. 8, it will stop |
e4541b67 OS |
233 | ;; as soon as the window size drops below that amount and will |
234 | ;; insert the item in the approximate centre of that window. I | |
235 | ;; got the idea for this feature after reading a very helpful | |
236 | ;; e-mail reply from Trey Jackson <trey@cs.berkeley.edu> who | |
237 | ;; corrected some of my awful coding and pointed me towards some | |
238 | ;; good reading. Thanks Trey! | |
01b864bc OS |
239 | ;; |
240 | ;; Things to do | |
241 | ;; | |
e4541b67 OS |
242 | ;; These originally were my ideas, but now also include all the |
243 | ;; suggestions that I included before forgetting them: | |
244 | ;; | |
e4541b67 OS |
245 | ;; o Fancy fonts for todo/top-priority buffer |
246 | ;; o Remove todo-prefix option in todo-top-priorities | |
247 | ;; o Rename category | |
248 | ;; o Move entry from one category to another one | |
249 | ;; o Entries which both have the generic */* prefix and a | |
250 | ;; "deadline" entry which are understood by diary, indicating | |
251 | ;; an event (unless marked by &) | |
252 | ;; o The optional COUNT variable of todo-forward-item should be | |
253 | ;; applied to the other functions performing similar tasks | |
254 | ;; o Modularization could be done for repeaded elements of | |
dad8ca4c | 255 | ;; the code, like the completing-read lines of code. |
e4541b67 | 256 | ;; o license / version function |
01b864bc OS |
257 | ;; o export to diary file |
258 | ;; o todo-report-bug | |
259 | ;; o GNATS support | |
e4541b67 OS |
260 | ;; o elide multiline (as in bbdb, or, to a lesser degree, in |
261 | ;; outline mode) | |
262 | ;; o rewrite complete package to store data as lisp objects | |
263 | ;; and have display modes for display, for diary export, | |
264 | ;; etc. (Richard Stallman pointed out this is a bad idea) | |
265 | ;; o so base todo-mode.el on generic-mode.el instead | |
01b864bc | 266 | ;; |
e4541b67 | 267 | ;; History and Gossip |
01b864bc | 268 | ;; |
e4541b67 OS |
269 | ;; Many thanks to all the ones who have contributed to the |
270 | ;; evolution of this package! I hope I have listed all of you | |
271 | ;; somewhere in the documentation or at least in the RCS history! | |
01b864bc | 272 | ;; |
e4541b67 OS |
273 | ;; Enjoy this package and express your gratitude by sending nice |
274 | ;; things to my parents' address! | |
01b864bc OS |
275 | ;; |
276 | ;; Oliver Seidel | |
e4541b67 | 277 | ;; (Lessingstr. 8, 65760 Eschborn, Federal Republic of Germany) |
7e6ed9b9 | 278 | |
7c896f63 OS |
279 | ;;; Code: |
280 | ||
9278c60d DL |
281 | (eval-when-compile |
282 | (require 'outline) | |
283 | (require 'calendar) | |
284 | ;; Calendar dynamic bondage: | |
285 | (defvar date) | |
286 | (defvar entry)) | |
287 | (autoload 'time-stamp-string "time-stamp") | |
85b3b166 | 288 | |
3cb152f9 OS |
289 | ;; User-configurable variables: |
290 | ||
85b3b166 OS |
291 | (defgroup todo nil |
292 | "Maintain a list of todo items." | |
a554b301 | 293 | :version "21.1" |
85b3b166 OS |
294 | :group 'calendar) |
295 | ||
a554b301 | 296 | (defcustom todo-prefix "*/*" |
85b3b166 OS |
297 | "*TODO mode prefix for entries. |
298 | ||
299 | This is useful in conjunction with `calendar' and `diary' if you use | |
300 | ||
301 | #include \"~/.todo-do\" | |
302 | ||
303 | in your diary file to include your todo list file as part of your | |
304 | diary. With the default value \"*/*\" the diary displays each entry | |
305 | every day and it may also be marked on every day of the calendar. | |
306 | Using \"&%%(equal (calendar-current-date) date)\" instead will only | |
307 | show and mark todo entreis for today, but may slow down processing of | |
308 | the diary file somewhat." | |
309 | :type 'string | |
310 | :group 'todo) | |
a554b301 | 311 | (defcustom todo-file-do "~/.todo-do" |
85b3b166 OS |
312 | "*TODO mode list file." |
313 | :type 'file | |
314 | :group 'todo) | |
a554b301 | 315 | (defcustom todo-file-done "~/.todo-done" |
85b3b166 OS |
316 | "*TODO mode archive file." |
317 | :type 'file | |
318 | :group 'todo) | |
319 | (defcustom todo-mode-hook nil | |
320 | "*TODO mode hooks." | |
321 | :type 'hook | |
322 | :group 'todo) | |
323 | (defcustom todo-edit-mode-hook nil | |
324 | "*TODO Edit mode hooks." | |
325 | :type 'hook | |
326 | :group 'todo) | |
327 | (defcustom todo-insert-threshold 0 | |
328 | "*TODO mode insertion accuracy. | |
329 | ||
330 | If you have 8 items in your TODO list, then you may get asked 4 | |
331 | questions by the binary insertion algorithm. However, you may not | |
332 | really have a need for such accurate priorities amongst your TODO | |
333 | items. If you now think about the binary insertion halfing the size | |
334 | of the window each time, then the threshhold is the window size at | |
335 | which it will stop. If you set the threshhold to zero, the upper and | |
336 | lower bound will coincide at the end of the loop and you will insert | |
337 | your item just before that point. If you set the threshhold to, | |
338 | e.g. 8, it will stop as soon as the window size drops below that | |
339 | amount and will insert the item in the approximate centre of that | |
340 | window." | |
341 | :type 'integer | |
342 | :group 'todo) | |
01b864bc | 343 | (defvar todo-edit-buffer " *TODO Edit*" "TODO Edit buffer name.") |
85b3b166 | 344 | (defcustom todo-file-top "~/.todo-top" |
f1757bdd | 345 | "*TODO mode top priorities file. |
85b3b166 | 346 | |
f1757bdd | 347 | Not in TODO format, but diary compatible. |
85b3b166 OS |
348 | Automatically generated when `todo-save-top-priorities' is non-nil." |
349 | :type 'string | |
350 | :group 'todo) | |
351 | ||
352 | (defcustom todo-print-function 'ps-print-buffer-with-faces | |
353 | "*Function to print the current buffer." | |
354 | :type 'symbol | |
355 | :group 'todo) | |
356 | (defcustom todo-show-priorities 1 | |
357 | "*Default number of priorities to show by \\[todo-top-priorities]. | |
358 | 0 means show all entries." | |
359 | :type 'integer | |
360 | :group 'todo) | |
361 | (defcustom todo-print-priorities 0 | |
362 | "*Default number of priorities to print by \\[todo-print]. | |
363 | 0 means print all entries." | |
364 | :type 'integer | |
365 | :group 'todo) | |
366 | (defcustom todo-remove-separator t | |
89802f43 | 367 | "*Non-nil to remove category separators in \ |
85b3b166 OS |
368 | \\[todo-top-priorities] and \\[todo-print]." |
369 | :type 'boolean | |
370 | :group 'todo) | |
371 | (defcustom todo-save-top-priorities-too t | |
a554b301 | 372 | "*Non-nil makes `todo-save' automatically save top-priorities in `todo-file-top'." |
85b3b166 OS |
373 | :type 'boolean |
374 | :group 'todo) | |
e4541b67 | 375 | |
7c896f63 OS |
376 | ;; Thanks for the ISO time stamp format go to Karl Eichwalder <ke@suse.de> |
377 | ;; My format string for the appt.el package is "%3b %2d, %y, %02I:%02M%p". | |
378 | ;; | |
85b3b166 | 379 | (defcustom todo-time-string-format |
bd40f1f2 | 380 | "%04y-%02m-%02d %02H:%02M" |
85b3b166 OS |
381 | "*TODO mode time string format for done entries. |
382 | For details see the variable `time-stamp-format'." | |
383 | :type 'string | |
384 | :group 'todo) | |
385 | ||
386 | (defcustom todo-entry-prefix-function 'todo-entry-timestamp-initials | |
387 | "*Function producing text to insert at start of todo entry." | |
388 | :type 'symbol | |
389 | :group 'todo) | |
390 | (defcustom todo-initials (or (getenv "INITIALS") (user-login-name)) | |
391 | "*Initials of todo item author." | |
392 | :type 'string | |
393 | :group 'todo) | |
e4541b67 OS |
394 | |
395 | (defun todo-entry-timestamp-initials () | |
f1757bdd | 396 | "Prepend timestamp and your initials to the head of a TODO entry." |
e4541b67 OS |
397 | (let ((time-stamp-format todo-time-string-format)) |
398 | (concat (time-stamp-string) " " todo-initials ": "))) | |
399 | ||
cf1ebf43 OS |
400 | ;; Set up some helpful context ... |
401 | ||
9278c60d DL |
402 | (defvar todo-categories nil |
403 | "TODO categories.") | |
404 | (defvar todo-cats nil | |
85b3b166 OS |
405 | "Old variable for holding the TODO categories. |
406 | Use `todo-categories' instead.") | |
9278c60d DL |
407 | (defvar todo-previous-line 0 |
408 | "Previous line asked about.") | |
409 | (defvar todo-previous-answer 0 | |
410 | "Previous answer got.") | |
411 | (defvar todo-category-number 0 | |
412 | "TODO category number.") | |
e4541b67 OS |
413 | |
414 | (defvar todo-category-sep (make-string 75 ?-) | |
415 | "Category separator.") | |
416 | (defvar todo-category-beg " --- " | |
417 | "Category start separator to be prepended onto category name.") | |
418 | (defvar todo-category-end "--- End" | |
419 | "Separator after a category.") | |
420 | (defvar todo-header "-*- mode: todo; " | |
421 | "Header of todo files.") | |
422 | ||
cf1ebf43 OS |
423 | ;; --------------------------------------------------------------------------- |
424 | ||
9278c60d | 425 | (defvar todo-mode-map |
3d8105fb OS |
426 | (let ((map (make-keymap))) |
427 | (suppress-keymap map t) | |
bd40f1f2 OS |
428 | (define-key map "?" 'todo-help) |
429 | (define-key map " " 'todo-hide-show-subtree) | |
7f6241ea OS |
430 | (define-key map "+" 'todo-forward-category) |
431 | (define-key map "-" 'todo-backward-category) | |
1966902e | 432 | (define-key map "d" 'todo-file-item) ;done/delete |
7f6241ea OS |
433 | (define-key map "e" 'todo-edit-item) |
434 | (define-key map "E" 'todo-edit-multiline) | |
435 | (define-key map "f" 'todo-file-item) | |
436 | (define-key map "i" 'todo-insert-item) | |
d145aa83 | 437 | (define-key map "I" 'todo-insert-item-here) |
e4541b67 | 438 | (define-key map "j" 'todo-jump-to-category) |
7f6241ea OS |
439 | (define-key map "k" 'todo-delete-item) |
440 | (define-key map "l" 'todo-lower-item) | |
441 | (define-key map "n" 'todo-forward-item) | |
442 | (define-key map "p" 'todo-backward-item) | |
e4541b67 | 443 | (define-key map "P" 'todo-print) |
7f6241ea OS |
444 | (define-key map "q" 'todo-quit) |
445 | (define-key map "r" 'todo-raise-item) | |
446 | (define-key map "s" 'todo-save) | |
f1757bdd | 447 | (define-key map "S" 'todo-save-top-priorities) |
e4541b67 | 448 | (define-key map "t" 'todo-top-priorities) |
9278c60d DL |
449 | map) |
450 | "TODO mode keymap.") | |
451 | ||
452 | (defun todo-position (item list) | |
453 | "Return the position of the element in LIST testing `equal' to ITEM. | |
454 | Return nil if ITEM not found." | |
455 | (let ((pos 0) | |
456 | found) | |
457 | (while list | |
458 | (if (equal item (pop list)) | |
459 | (setq list nil | |
460 | found pos) | |
461 | (setq pos (1+ pos)))) | |
462 | found)) | |
3cb152f9 | 463 | |
7f6241ea OS |
464 | (defun todo-category-select () |
465 | "Make TODO mode display the current category correctly." | |
466 | (let ((name (nth todo-category-number todo-categories))) | |
579e1c67 | 467 | (setq mode-line-buffer-identification |
6fe3681b | 468 | (concat "Category: " (format "%18s" name))) |
da2ee685 OS |
469 | (widen) |
470 | (goto-char (point-min)) | |
7f6241ea | 471 | (search-forward-regexp |
e4541b67 OS |
472 | (concat "^" |
473 | (regexp-quote (concat todo-prefix todo-category-beg name)) | |
474 | "$")) | |
9278c60d | 475 | (let ((begin (1+ (line-end-position)))) |
e4541b67 | 476 | (search-forward-regexp (concat "^" todo-category-end)) |
9278c60d | 477 | (narrow-to-region begin (line-beginning-position)) |
7f6241ea OS |
478 | (goto-char (point-min))))) |
479 | (defalias 'todo-cat-slct 'todo-category-select) | |
480 | ||
bd40f1f2 OS |
481 | (defun todo-help () "Show TODO mode help." |
482 | (interactive) | |
483 | (describe-function 'todo-mode)) | |
484 | ||
9278c60d DL |
485 | (defun todo-hide-show-subtree () |
486 | "Hide or Show subtrees in the TODO list." | |
bd40f1f2 OS |
487 | (interactive) |
488 | (save-excursion | |
489 | (end-of-line) | |
490 | (if (outline-visible) | |
491 | (hide-subtree) | |
492 | (show-subtree)))) | |
493 | ||
9278c60d DL |
494 | (defun todo-forward-category () |
495 | "Go forward to TODO list of next category." | |
da2ee685 | 496 | (interactive) |
7f6241ea | 497 | (setq todo-category-number |
01b864bc | 498 | (mod (1+ todo-category-number) (length todo-categories))) |
7f6241ea OS |
499 | (todo-category-select)) |
500 | (defalias 'todo-cmd-forw 'todo-forward-category) | |
da2ee685 | 501 | |
9278c60d DL |
502 | (defun todo-backward-category () |
503 | "Go back to TODO list of previous category." | |
da2ee685 | 504 | (interactive) |
7f6241ea | 505 | (setq todo-category-number |
01b864bc | 506 | (mod (1- todo-category-number) (length todo-categories))) |
7f6241ea OS |
507 | (todo-category-select)) |
508 | (defalias 'todo-cmd-back 'todo-backward-category) | |
da2ee685 | 509 | |
9278c60d DL |
510 | (defun todo-backward-item () |
511 | "Select previous entry of TODO list." | |
3cb152f9 | 512 | (interactive) |
7f6241ea | 513 | (search-backward-regexp (concat "^" (regexp-quote todo-prefix)) nil t) |
cf1ebf43 | 514 | (message "")) |
7f6241ea | 515 | (defalias 'todo-cmd-prev 'todo-backward-item) |
3cb152f9 | 516 | |
e4541b67 | 517 | (defun todo-forward-item (&optional count) |
85b3b166 | 518 | "Select COUNT-th next entry of TODO list." |
e4541b67 OS |
519 | (interactive "P") |
520 | (if (listp count) (setq count (car count))) | |
7f6241ea | 521 | (end-of-line) |
e4541b67 OS |
522 | (search-forward-regexp (concat "^" (regexp-quote todo-prefix)) |
523 | nil 'goto-end count) | |
7f6241ea | 524 | (beginning-of-line) |
cf1ebf43 | 525 | (message "")) |
7f6241ea | 526 | (defalias 'todo-cmd-next 'todo-forward-item) |
3cb152f9 | 527 | |
7f6241ea | 528 | (defun todo-save () "Save the TODO list." |
da2ee685 | 529 | (interactive) |
f1757bdd | 530 | (save-buffer) |
89802f43 | 531 | (if todo-save-top-priorities-too (todo-save-top-priorities))) |
7f6241ea | 532 | (defalias 'todo-cmd-save 'todo-save) |
da2ee685 | 533 | |
7f6241ea | 534 | (defun todo-quit () "Done with TODO list for now." |
3cb152f9 | 535 | (interactive) |
da2ee685 | 536 | (widen) |
f1757bdd | 537 | (todo-save) |
7e6ed9b9 | 538 | (message "") |
cf1ebf43 | 539 | (bury-buffer)) |
7f6241ea | 540 | (defalias 'todo-cmd-done 'todo-quit) |
3cb152f9 | 541 | |
7f6241ea | 542 | (defun todo-edit-item () "Edit current TODO list entry." |
3cb152f9 | 543 | (interactive) |
7f6241ea OS |
544 | (let ((item (todo-item-string))) |
545 | (if (todo-string-multiline-p item) | |
01b864bc | 546 | (todo-edit-multiline) |
7f6241ea | 547 | (let ((new (read-from-minibuffer "Edit: " item))) |
01b864bc | 548 | (todo-remove-item) |
89802f43 | 549 | (insert new ?\n) |
01b864bc OS |
550 | (todo-backward-item) |
551 | (message ""))))) | |
7f6241ea OS |
552 | (defalias 'todo-cmd-edit 'todo-edit-item) |
553 | ||
554 | (defun todo-edit-multiline () | |
555 | "Set up a buffer for editing a multiline TODO list entry." | |
556 | (interactive) | |
557 | (let ((buffer-name (generate-new-buffer-name todo-edit-buffer))) | |
e4541b67 OS |
558 | (switch-to-buffer |
559 | (make-indirect-buffer | |
bd40f1f2 | 560 | (find-buffer-visiting todo-file-do) buffer-name)) |
2186b974 | 561 | (message "To exit, simply kill this buffer and return to list.") |
7f6241ea OS |
562 | (todo-edit-mode) |
563 | (narrow-to-region (todo-item-start) (todo-item-end)))) | |
3cb152f9 | 564 | |
dad8ca4c | 565 | (defun todo-add-category (cat) |
85b3b166 | 566 | "Add new category CAT to the TODO list." |
6b04f517 | 567 | (interactive "sCategory: ") |
3cb152f9 | 568 | (save-window-excursion |
a554b301 | 569 | (add-to-list 'todo-categories cat) |
3cb152f9 | 570 | (find-file todo-file-do) |
da2ee685 OS |
571 | (widen) |
572 | (goto-char (point-min)) | |
573 | (let ((posn (search-forward "-*- mode: todo; " 17 t))) | |
89802f43 | 574 | (if posn |
01b864bc | 575 | (progn |
89802f43 DL |
576 | (goto-char posn) |
577 | (kill-line)) | |
578 | (insert "-*- mode: todo; \n") | |
579 | (backward-char))) | |
7f6241ea | 580 | (insert (format "todo-categories: %S; -*-" todo-categories)) |
89802f43 | 581 | (forward-char) |
e4541b67 OS |
582 | (insert (format "%s%s%s\n%s\n%s %s\n" |
583 | todo-prefix todo-category-beg cat | |
dad8ca4c | 584 | todo-category-end |
bd40f1f2 OS |
585 | todo-prefix todo-category-sep)) |
586 | (save-buffer)) | |
cf1ebf43 | 587 | 0) |
da2ee685 | 588 | |
4dc1a160 | 589 | (defun todo-add-item-non-interactively (new-item category) |
85b3b166 | 590 | "Insert NEW-ITEM in TODO list as a new entry in CATEGORY." |
4cbc9d5a | 591 | (save-excursion |
49b2ae0e OS |
592 | (todo-show)) |
593 | (save-excursion | |
e4541b67 OS |
594 | (if (string= "" category) |
595 | (setq category (nth todo-category-number todo-categories))) | |
bd40f1f2 | 596 | (setq todo-category-number |
9278c60d | 597 | (or (todo-position category todo-categories) |
bd40f1f2 | 598 | (todo-add-category category))) |
4dc1a160 OS |
599 | (todo-show) |
600 | (setq todo-previous-line 0) | |
601 | (let ((top 1) | |
602 | (bottom (1+ (count-lines (point-min) (point-max))))) | |
603 | (while (> (- bottom top) todo-insert-threshold) | |
604 | (let* ((current (/ (+ top bottom) 2)) | |
605 | (answer (if (< current bottom) | |
89802f43 | 606 | (todo-more-important-p current)))) |
4dc1a160 OS |
607 | (if answer |
608 | (setq bottom current) | |
609 | (setq top (1+ current))))) | |
610 | (setq top (/ (+ top bottom) 2)) | |
611 | ;; goto-line doesn't have the desired behavior in a narrowed buffer | |
612 | (goto-char (point-min)) | |
613 | (forward-line (1- top))) | |
89802f43 | 614 | (insert new-item ?\n) |
7f6241ea | 615 | (todo-backward-item) |
bd40f1f2 OS |
616 | (progn ;;; horrible os10000 hack to make items appear when inserting into empty buffer |
617 | (widen) | |
618 | (show-all) | |
619 | (todo-forward-category) | |
620 | (todo-backward-category)) | |
f1757bdd | 621 | (todo-save) |
3d8105fb | 622 | (message ""))) |
4cbc9d5a | 623 | |
6c7331ff | 624 | ;;;###autoload |
89802f43 | 625 | (defun todo-insert-item (arg) |
85b3b166 OS |
626 | "Insert new TODO list entry. |
627 | With a prefix argument solicit the category, otherwise use the current | |
628 | category." | |
4cbc9d5a | 629 | (interactive "P") |
49b2ae0e | 630 | (save-excursion |
1966902e OS |
631 | (if (not (string-equal mode-name "TODO")) (todo-show)) |
632 | (let* ((new-item (concat todo-prefix " " | |
633 | (read-from-minibuffer | |
634 | "New TODO entry: " | |
635 | (if todo-entry-prefix-function | |
636 | (funcall todo-entry-prefix-function))))) | |
637 | (categories todo-categories) | |
638 | (history (cons 'categories (1+ todo-category-number))) | |
639 | (current-category (nth todo-category-number todo-categories)) | |
dad8ca4c | 640 | (category |
89802f43 | 641 | (if arg |
1966902e | 642 | current-category |
dad8ca4c | 643 | (completing-read |
89802f43 DL |
644 | (concat "Category [" current-category "]: ") |
645 | (todo-category-alist) nil nil nil history current-category)))) | |
4dc1a160 | 646 | (todo-add-item-non-interactively new-item category)))) |
4cbc9d5a | 647 | |
7f6241ea | 648 | (defalias 'todo-cmd-inst 'todo-insert-item) |
3d8105fb | 649 | |
d145aa83 OS |
650 | (defun todo-insert-item-here () |
651 | "Insert new TODO list entry under the cursor." | |
4dc1a160 OS |
652 | (interactive "") |
653 | (save-excursion | |
654 | (if (not (string-equal mode-name "TODO")) (todo-show)) | |
655 | (let* ((new-item (concat todo-prefix " " | |
656 | (read-from-minibuffer | |
657 | "New TODO entry: " | |
658 | (if todo-entry-prefix-function | |
659 | (funcall todo-entry-prefix-function)))))) | |
660 | (insert (concat new-item "\n"))))) | |
d145aa83 | 661 | |
01b864bc | 662 | (defun todo-more-important-p (line) |
7f6241ea OS |
663 | "Ask whether entry is more important than the one at LINE." |
664 | (if (not (equal todo-previous-line line)) | |
3d8105fb | 665 | (progn |
7f6241ea | 666 | (setq todo-previous-line line) |
3d8105fb | 667 | (goto-char (point-min)) |
7f6241ea | 668 | (forward-line (1- todo-previous-line)) |
01b864bc OS |
669 | (let ((item (todo-item-string-start))) |
670 | (setq todo-previous-answer | |
671 | (y-or-n-p (concat "More important than '" item "'? ")))))) | |
7f6241ea OS |
672 | todo-previous-answer) |
673 | (defalias 'todo-ask-p 'todo-more-important-p) | |
674 | ||
675 | (defun todo-delete-item () "Delete current TODO list entry." | |
3cb152f9 OS |
676 | (interactive) |
677 | (if (> (count-lines (point-min) (point-max)) 0) | |
7f6241ea | 678 | (let* ((todo-entry (todo-item-string-start)) |
01b864bc OS |
679 | (todo-answer (y-or-n-p (concat "Permanently remove '" |
680 | todo-entry "'? ")))) | |
89802f43 DL |
681 | (when todo-answer |
682 | (todo-remove-item) | |
683 | (todo-backward-item)) | |
01b864bc | 684 | (message "")) |
7f6241ea OS |
685 | (error "No TODO list entry to delete"))) |
686 | (defalias 'todo-cmd-kill 'todo-delete-item) | |
3cb152f9 | 687 | |
7f6241ea | 688 | (defun todo-raise-item () "Raise priority of current entry." |
8cdc3b3d | 689 | (interactive) |
7f6241ea OS |
690 | (if (> (count-lines (point-min) (point)) 0) |
691 | (let ((item (todo-item-string))) | |
01b864bc OS |
692 | (todo-remove-item) |
693 | (todo-backward-item) | |
694 | (save-excursion | |
89802f43 | 695 | (insert item ?\n)) |
01b864bc | 696 | (message "")) |
7f6241ea | 697 | (error "No TODO list entry to raise"))) |
a554b301 | 698 | (defalias 'todo-cmd-raise 'todo-raise-item) |
8cdc3b3d | 699 | |
7f6241ea | 700 | (defun todo-lower-item () "Lower priority of current entry." |
8cdc3b3d | 701 | (interactive) |
e4541b67 OS |
702 | (if (> (count-lines (point) (point-max)) 1) |
703 | ;; Assume there is a final newline | |
7f6241ea | 704 | (let ((item (todo-item-string))) |
01b864bc OS |
705 | (todo-remove-item) |
706 | (todo-forward-item) | |
707 | (save-excursion | |
89802f43 | 708 | (insert item ?\n)) |
01b864bc | 709 | (message "")) |
7f6241ea OS |
710 | (error "No TODO list entry to lower"))) |
711 | (defalias 'todo-cmd-lowr 'todo-lower-item) | |
8cdc3b3d | 712 | |
0561decb | 713 | (defun todo-file-item (&optional comment) |
a554b301 | 714 | "File the current TODO list entry away, annotated with an optional COMMENT." |
0561decb OS |
715 | (interactive "sComment: ") |
716 | (or (> (count-lines (point-min) (point-max)) 0) | |
717 | (error "No TODO list entry to file away")) | |
718 | (let ((time-stamp-format todo-time-string-format)) | |
89802f43 DL |
719 | (when (and comment (> (length comment) 0)) |
720 | (goto-char (todo-item-end)) | |
721 | (insert | |
722 | (if (save-excursion (beginning-of-line) | |
723 | (looking-at (regexp-quote todo-prefix))) | |
724 | " " | |
725 | "\n\t") | |
726 | "(" comment ")")) | |
0561decb OS |
727 | (goto-char (todo-item-end)) |
728 | (insert " [" (nth todo-category-number todo-categories) "]") | |
729 | (goto-char (todo-item-start)) | |
730 | (let ((temp-point (point))) | |
731 | (if (looking-at (regexp-quote todo-prefix)) | |
732 | (replace-match (time-stamp-string)) | |
733 | ;; Standard prefix -> timestamp | |
734 | ;; Else prefix non-standard item start with timestamp | |
735 | (insert (time-stamp-string))) | |
736 | (append-to-file temp-point (1+ (todo-item-end)) todo-file-done) | |
737 | (delete-region temp-point (1+ (todo-item-end)))) | |
738 | (todo-backward-item) | |
739 | (message ""))) | |
3cb152f9 OS |
740 | |
741 | ;; --------------------------------------------------------------------------- | |
742 | ||
7f6241ea OS |
743 | ;; Utility functions: |
744 | ||
e4541b67 OS |
745 | (defun todo-top-priorities (&optional nof-priorities category-pr-page) |
746 | "List top priorities for each category. | |
747 | ||
748 | Number of entries for each category is given by NOF-PRIORITIES which | |
749 | defaults to \'todo-show-priorities\'. | |
750 | ||
751 | If CATEGORY-PR-PAGE is non-nil, a page separator \'^L\' is inserted | |
752 | between each category." | |
753 | ||
754 | (interactive "P") | |
755 | (or nof-priorities (setq nof-priorities todo-show-priorities)) | |
756 | (if (listp nof-priorities) ;universal argument | |
757 | (setq nof-priorities (car nof-priorities))) | |
a554b301 | 758 | (let ((todo-print-buffer-name " *todo-tmp*") |
85b3b166 OS |
759 | ;;(todo-print-category-number 0) |
760 | (todo-category-break (if category-pr-page "\f" "")) | |
e4541b67 OS |
761 | (cat-end |
762 | (concat | |
763 | (if todo-remove-separator | |
764 | (concat todo-category-end "\n" | |
765 | (regexp-quote todo-prefix) " " todo-category-sep "\n") | |
766 | (concat todo-category-end "\n")))) | |
767 | beg end) | |
768 | (todo-show) | |
769 | (save-excursion | |
770 | (save-restriction | |
771 | (widen) | |
85b3b166 OS |
772 | (copy-to-buffer todo-print-buffer-name (point-min) (point-max)) |
773 | (set-buffer todo-print-buffer-name) | |
e4541b67 | 774 | (goto-char (point-min)) |
89802f43 DL |
775 | (when (re-search-forward (regexp-quote todo-header) nil t) |
776 | (beginning-of-line 1) | |
777 | (kill-line)) ;Remove mode line | |
e4541b67 OS |
778 | (while (re-search-forward ;Find category start |
779 | (regexp-quote (concat todo-prefix todo-category-beg)) | |
780 | nil t) | |
9278c60d | 781 | (setq beg (+ (line-end-position) 1)) ;Start of first entry. |
e4541b67 OS |
782 | (re-search-forward cat-end nil t) |
783 | (setq end (match-beginning 0)) | |
784 | (replace-match todo-category-break) | |
785 | (narrow-to-region beg end) ;In case we have too few entries. | |
786 | (goto-char (point-min)) | |
787 | (if (= 0 nof-priorities) ;Traverse entries. | |
89802f43 | 788 | (goto-char end) ;All entries |
e4541b67 OS |
789 | (todo-forward-item nof-priorities)) |
790 | (setq beg (point)) | |
791 | (delete-region beg end) | |
792 | (widen)) | |
f1757bdd | 793 | (and (looking-at "\f") (replace-match "")) ;Remove trailing form-feed. |
e4541b67 OS |
794 | (goto-char (point-min)) ;Due to display buffer |
795 | )) | |
796 | ;; Could have used switch-to-buffer as it has a norecord argument, | |
797 | ;; which is nice when we are called from e.g. todo-print. | |
f1757bdd | 798 | ;; Else we could have used pop-to-buffer. |
85b3b166 | 799 | (display-buffer todo-print-buffer-name) |
e4541b67 | 800 | (message "Type C-x 1 to remove %s window. M-C-v to scroll the help." |
9278c60d | 801 | todo-print-buffer-name))) |
e4541b67 | 802 | |
f1757bdd OS |
803 | (defun todo-save-top-priorities (&optional nof-priorities) |
804 | "Save top priorities for each category in `todo-file-top'. | |
805 | ||
806 | Number of entries for each category is given by NOF-PRIORITIES which | |
807 | defaults to `todo-show-priorities'." | |
808 | (interactive "P") | |
9278c60d DL |
809 | (with-temp-buffer |
810 | (todo-top-priorities nof-priorities) | |
811 | (write-file todo-file-top))) | |
f1757bdd | 812 | |
e4541b67 OS |
813 | ;;;###autoload |
814 | (defun todo-print (&optional category-pr-page) | |
a554b301 | 815 | "Print todo summary using `todo-print-function'. |
e4541b67 OS |
816 | If CATEGORY-PR-PAGE is non-nil, a page separator \'^L\' is inserted |
817 | between each category. | |
818 | ||
819 | Number of entries for each category is given by | |
820 | \'todo-print-priorities\'." | |
821 | (interactive "P") | |
9278c60d DL |
822 | (with-temp-buffer |
823 | (todo-top-priorities todo-print-priorities | |
824 | category-pr-page) | |
825 | (funcall todo-print-function) | |
826 | (message "Todo printing done."))) | |
e4541b67 OS |
827 | |
828 | (defun todo-jump-to-category () | |
829 | "Jump to a category. Default is previous category." | |
830 | (interactive) | |
831 | (let* ((categories todo-categories) | |
bd40f1f2 | 832 | (history (cons 'categories (1+ todo-category-number))) |
dad8ca4c | 833 | (category (completing-read |
e4541b67 OS |
834 | (concat "Category [" |
835 | (nth todo-category-number todo-categories) "]: ") | |
836 | (todo-category-alist) nil nil nil history))) | |
837 | (if (string= "" category) | |
838 | (setq category (nth todo-category-number todo-categories))) | |
839 | (setq todo-category-number | |
9278c60d | 840 | (or (todo-position category todo-categories) |
bd40f1f2 | 841 | (todo-add-category category))) |
e4541b67 OS |
842 | (todo-show))) |
843 | ||
9278c60d DL |
844 | (defun todo-line-string () |
845 | "Return current line in buffer as a string." | |
846 | (buffer-substring (line-beginning-position) (line-end-position))) | |
7f6241ea OS |
847 | |
848 | (defun todo-item-string-start () | |
849 | "Return the start of this TODO list entry as a string." | |
850 | ;; Suitable for putting in the minibuffer when asking the user | |
851 | (let ((item (todo-item-string))) | |
852 | (if (> (length item) 60) | |
01b864bc | 853 | (setq item (concat (substring item 0 56) "..."))) |
7f6241ea OS |
854 | item)) |
855 | ||
9278c60d DL |
856 | (defun todo-item-start () |
857 | "Return point at start of current TODO list item." | |
7f6241ea OS |
858 | (save-excursion |
859 | (beginning-of-line) | |
860 | (if (not (looking-at (regexp-quote todo-prefix))) | |
01b864bc OS |
861 | (search-backward-regexp |
862 | (concat "^" (regexp-quote todo-prefix)) nil t)) | |
7f6241ea OS |
863 | (point))) |
864 | ||
9278c60d DL |
865 | (defun todo-item-end () |
866 | "Return point at end of current TODO list item." | |
7f6241ea OS |
867 | (save-excursion |
868 | (end-of-line) | |
e4541b67 OS |
869 | (search-forward-regexp |
870 | (concat "^" (regexp-quote todo-prefix)) nil 'goto-end) | |
9278c60d | 871 | (1- (line-beginning-position)))) |
7f6241ea | 872 | |
9278c60d DL |
873 | (defun todo-remove-item () |
874 | "Delete the current entry from the TODO list." | |
7f6241ea OS |
875 | (delete-region (todo-item-start) (1+ (todo-item-end)))) |
876 | ||
877 | (defun todo-item-string () "Return current TODO list entry as a string." | |
878 | (buffer-substring (todo-item-start) (todo-item-end))) | |
879 | ||
880 | (defun todo-string-count-lines (string) | |
881 | "Return the number of lines STRING spans." | |
882 | (length (split-string string "\n"))) | |
883 | ||
884 | (defun todo-string-multiline-p (string) | |
85b3b166 | 885 | "Return non-nil if STRING spans several lines." |
7f6241ea OS |
886 | (> (todo-string-count-lines string) 1)) |
887 | ||
888 | (defun todo-category-alist () | |
85b3b166 | 889 | "Generate an alist for use in `completing-read' from `todo-categories'." |
a554b301 | 890 | (mapcar #'list todo-categories)) |
7f6241ea | 891 | |
da2ee685 OS |
892 | ;; --------------------------------------------------------------------------- |
893 | ||
a554b301 DL |
894 | (easy-menu-define |
895 | todo-menu todo-mode-map "Todo Menu" | |
896 | '("Todo" | |
897 | ["Next category" todo-forward-category t] | |
898 | ["Previous category" todo-backward-category t] | |
899 | ["Jump to category" todo-jump-to-category t] | |
900 | ["Show top priority items" todo-top-priorities t] | |
901 | ["Print categories" todo-print t] | |
902 | "---" | |
903 | ["Edit item" todo-edit-item t] | |
904 | ["File item" todo-file-item t] | |
905 | ["Insert new item" todo-insert-item t] | |
906 | ["Insert item here" todo-insert-item-here t] | |
907 | ["Kill item" todo-delete-item t] | |
908 | "---" | |
909 | ["Lower item priority" todo-lower-item t] | |
910 | ["Raise item priority" todo-raise-item t] | |
911 | "---" | |
912 | ["Next item" todo-forward-item t] | |
913 | ["Previous item" todo-backward-item t] | |
914 | "---" | |
915 | ["Save" todo-save t] | |
916 | ["Save Top Priorities" todo-save-top-priorities t] | |
917 | "---" | |
918 | ["Quit" todo-quit t] | |
919 | )) | |
a360be79 | 920 | |
e4541b67 | 921 | ;; As calendar reads .todo-do before todo-mode is loaded. |
6c7331ff | 922 | ;;;###autoload |
a554b301 DL |
923 | (defun todo-mode () |
924 | "Major mode for editing TODO lists. | |
925 | ||
926 | \\{todo-mode-map}" | |
3cb152f9 | 927 | (interactive) |
3cb152f9 OS |
928 | (setq major-mode 'todo-mode) |
929 | (setq mode-name "TODO") | |
930 | (use-local-map todo-mode-map) | |
49c48a1b | 931 | (easy-menu-add todo-menu) |
bd40f1f2 | 932 | (setq fill-prefix "\t\t") |
a554b301 DL |
933 | (let ((prefix (regexp-quote todo-prefix))) |
934 | (setq paragraph-separate prefix) | |
935 | (setq outline-regexp prefix)) | |
bd40f1f2 | 936 | (outline-minor-mode 1) |
a554b301 DL |
937 | (goto-char (point-min)) |
938 | (outline-next-heading) ; get past -*- line | |
bd40f1f2 OS |
939 | (hide-other) |
940 | (auto-fill-mode 1) | |
49c48a1b | 941 | (run-hooks 'todo-mode-hook)) |
da2ee685 | 942 | |
5d035cad | 943 | ;; Read about this function in the setup instructions above! |
6c7331ff | 944 | ;;;###autoload |
5d035cad | 945 | (defun todo-cp () |
a554b301 | 946 | "Make a diary entry appear only in the current date's diary." |
5d035cad | 947 | (if (equal (calendar-current-date) date) |
a554b301 | 948 | entry)) |
5d035cad | 949 | |
7f6241ea | 950 | (defun todo-edit-mode () |
a554b301 DL |
951 | "Major mode for editing items in the TODO list. |
952 | ||
953 | \\{todo-edit-mode-map}" | |
7f6241ea OS |
954 | (text-mode) |
955 | (setq major-mode 'todo-edit-mode) | |
956 | (setq mode-name "TODO Edit") | |
957 | (run-hooks 'todo-edit-mode-hook)) | |
958 | ||
6c7331ff | 959 | ;;;###autoload |
a554b301 DL |
960 | (defun todo-show () |
961 | "Show TODO list." | |
da2ee685 | 962 | (interactive) |
7f6241ea OS |
963 | (if (file-exists-p todo-file-do) |
964 | (find-file todo-file-do) | |
965 | (todo-initial-setup)) | |
89802f43 DL |
966 | (unless todo-categories |
967 | (if (null todo-cats) | |
968 | (error "Error in %s: No categories in list `todo-categories'" | |
969 | todo-file-do) | |
970 | (goto-char (point-min)) | |
971 | (and (search-forward "todo-cats:" nil t) | |
972 | (replace-match "todo-categories:")) | |
973 | (make-local-variable 'todo-categories) | |
974 | (setq todo-categories todo-cats))) | |
7f6241ea OS |
975 | (beginning-of-line) |
976 | (todo-category-select)) | |
977 | ||
a554b301 DL |
978 | (defun todo-initial-setup () |
979 | "Set up things to work properly in TODO mode." | |
da2ee685 | 980 | (find-file todo-file-do) |
7f6241ea OS |
981 | (erase-buffer) |
982 | (todo-mode) | |
983 | (todo-add-category "Todo")) | |
3cb152f9 | 984 | |
7c896f63 | 985 | (provide 'todo-mode) |
3cb152f9 OS |
986 | |
987 | ;; --------------------------------------------------------------------------- | |
7c896f63 | 988 | ;;; todo-mode.el ends here |
3cb152f9 | 989 | ;; --------------------------------------------------------------------------- |