;;; planner-diary.el --- Calendar and Diary integration for the Emacs Planner (planner.el) ;; Copyright (C) 2003 Thomas Gehrlein ;; Emacs Lisp Archive Entry ;; Filename: planner-diary.el ;; Version: 0.1 2003/04/22 ;; Keywords: hypermedia ;; Author: Thomas Gehrlein ;; Maintainer: Thomas Gehrlein ;; Description: Integrate the Emacs Planner with Calendar and Diary ;; URL: http://richip.dhs.org/~sachac/notebook/emacs/planner-diary.el ;; ChangeLog: Can be requested from the maintainer ;; Compatibility: Emacs20, Emacs21 ;; This file is not part of GNU Emacs. ;; This is free software; you can redistribute it and/or modify it under ;; the terms of the GNU General Public License as published by the Free ;; Software Foundation; either version 2, or (at your option) any later ;; version. ;; ;; This is distributed in the hope that it will be useful, but WITHOUT ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ;; for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. ;;; USAGE: ;; Place planner.el in your load path and add this to your .emacs: ;; ;; (require 'planner-diary) ;; ;; Don't use it with planner-insinuate-calendar. ;;; TODO ;; use defcustoms ;; write documentation ;;; THOUGHTS ;; There are 3 ways to use planner with calendar and diary: ;; 1) Use calendar for browsing the day plan pages. ;; Cool features: all days with day plan pages are marked. ">" and "<" move to ;; the next or previous page. (Ordinary diary entries should not be marked.) ;; Entry point: a command (planner-browse-calendar ??) What about key-bindings ;; for "n" and "N"? ;; 2) Display the day plan pages when you move in calendar. ;; Add a hook to calendar-move-hook. Add key-bindings for "n" and "N". ;; 3) Automatically update the diary section in day plan pages. ;; Add a function to planner-goto-hook. This work independent of the first 2. (require 'planner) (require 'diary-lib) (require 'calendar) ;;; user variables (defvar planner-diary-string "* Diary" "*Header for the diary section in a day plan page.") ;; Is not used anywhere ;; (defvar planner-diary-use-diary t ;; "*Non-nil means use the wonderful possibilities of planner-diary.") ;;; functions (defun planner-diary-get-diary-entries (date) "Get the diary entries for DATE. DATE is a list (month day year)." (save-window-excursion (let* ((fancy-diary-buffer "temporary-fancy-diary-buffer") (entries)) ;; TODO: wrap next line in ;; (flet ((message (&rest args) (ignore args))) (list-diary-entries date 1) (switch-to-buffer fancy-diary-buffer) ;; return empty string if buffer is empty (if (= (point-max) 1) (setq entries "") (setq entries ;; skip to ============= (buffer-substring (progn (goto-char (point-min)) (search-forward-regexp "^=+$") ; one or more = (1+ (point))) ;; remove final newline (progn (goto-char (point-max)) (when (bolp) (backward-char 1)) (point))))) (kill-buffer fancy-diary-buffer) entries))) (defun planner-diary-insert-diary (&optional force) "Insert the fancy diary for the day into the day plan file. If FORCE is non-nil, insert `planner-diary-string' at the beginning of the buffer if it is not there yet." ;; search for "^* Diary$", delete buffer content to the next "^* ", insert (interactive "P") ; raw prefix arg ;; sanity checks (unless (and (equal major-mode 'planner-mode) (string-match planner-date-regexp (buffer-name))) (error "Cannot insert diary in this buffer.")) (save-excursion (goto-char (point-min)) (or (re-search-forward (concat "^" planner-diary-string "$") (point-max) t) (when force (insert planner-diary-string "\n\n\n") (backward-char 3) t) (error "Cannot insert diary, no diary section in this buffer.")) ;; point is at the end of "* Diary" ;; (forward-char 1) (let ((beg (point)) (end (if (re-search-forward "^* " (point-max) t) (progn (beginning-of-line) (backward-char 1) (point)) (point-max)))) (delete-region beg end) ;; point is at the end of "* Diary" (let ((entries (planner-diary-get-diary-entries (planner-filename-to-calendar-date (buffer-name))))) (insert "\n\n") (unless (string= entries "") (insert entries "\n")))))) (defun planner-diary-insert-diary-maybe (&optional force) "Maybe insert the fancy diary for the day into the day plan file. If the current day is in the past, don't do anything. If FORCE is non-nil, insert `planner-diary-string' at the beginning of the buffer if it is not there yet." (interactive "P") (if (string< (buffer-name) (planner-today)) ;; we are in the past -> do nothing, message when interactive (when (interactive-p) (message "Date is in the past. No diary entries inserted.")) (if (string-match (buffer-name) planner-date-regexp) ;; today or future (planner-diary-insert-diary force)))) (defun planner-diary-show-day-plan-or-diary () "Show the day plan or diary entries for the date under point in calendar." (interactive) (or (planner-calendar-show) (view-diary-entries 1))) ;; C-cC-e happens to be free (define-key planner-mode-map [(control ?c) (control ?e)] 'planner-diary-insert-diary) (define-key calendar-mode-map "n" 'planner-calendar-goto) (define-key calendar-mode-map "N" 'planner-calendar-show) (add-hook 'planner-goto-hook 'planner-diary-insert-diary-maybe) (add-hook 'calendar-move-hook 'planner-diary-show-day-plan-or-diary) (provide 'planner-diary)