]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/notes-mode/notes-mode.el
Add notes-mode.
[gnu-emacs-elpa] / packages / notes-mode / notes-mode.el
diff --git a/packages/notes-mode/notes-mode.el b/packages/notes-mode/notes-mode.el
new file mode 100644 (file)
index 0000000..e8ad735
--- /dev/null
@@ -0,0 +1,728 @@
+
+;;;
+;;; notes-mode.el
+;;; $Id: notes-mode.el,v 1.71 2009/08/20 20:00:02 johnh Exp $
+;;;
+;;; Copyright (C) 1994-2007 by John Heidemann
+;;; Comments to <johnh@isi.edu>.
+;;;
+;;; This file is under the Gnu Public License.
+;;;
+
+(require 'notes-variables)
+(require 'notes-aux)
+
+(defvar notes-mode-hooks nil
+  "Hooks to run when entering notes-mode.")
+(defvar notes-load-mode-hooks nil
+  "Hooks to run when entering notes-mode is loaded.")
+
+(defconst notes-beginning-of-defun-regexp "^\\* .*\n\\-"
+  "Regexp matching the beginning of notes section.")
+
+(defvar notes-default-tab-binding nil
+  "Saved tab binding for notes-complete-subject.")
+(defvar notes-default-return-binding nil
+  "Saved return binding for notes-electric-return.")
+
+
+(defun notes-beginning-of-defun ()
+  "Go to the beginning of a notes ``section''."
+  (interactive)
+  (let
+      ((old-point (point)))
+    (beginning-of-line)
+    ;; handle starting on a title
+    (if (and (looking-at notes-beginning-of-defun-regexp)
+            (/= (point) old-point))
+       nil
+      (goto-char old-point)
+      (if (looking-at "^-")  ;; handle starting on the underline under a title
+         (forward-char 1))
+      (generic-beginning-of-defun notes-beginning-of-defun-regexp))))
+
+(defun notes-end-of-defun ()
+  "Go to the end of a notes ``section''."
+  (interactive)
+  (generic-end-of-defun notes-beginning-of-defun-regexp))
+
+(defun notes-follow-link (which)
+  "Go to the WHICH link for this topic.
+WHICH is either \"next\" or \"prev\".
+If there are no links for the current note,
+we go to the last note based upon the index file."
+  (let
+      (beginning-of-note
+       end-of-note
+       (start-buffer (current-buffer))
+       ;; We have to handle links in the same buffer,
+       ;; so the following code figure out where we go
+       ;; and returns it out of the save-excursion.
+       ;; If we end up in another buffer, we let the save-excursion
+       ;; leave the original buffer unchanged.  If we end up in
+       ;; the same buffer, we need to go wherever we end up.
+       ;; Can anyone suggest a better way?
+       (end-buffer-and-point
+       (save-excursion
+         (notes-end-of-defun)
+         (setq end-of-note (point))
+         (notes-beginning-of-defun)
+         (setq beginning-of-note (point))
+         (if (and (= beginning-of-note 1) (not (looking-at notes-beginning-of-defun-regexp)))
+             (progn
+               ;; When "above" the first note, search to end of first
+               ;; real note (otherwise end-of-note is just the start
+               ;; of the first real note and there are no links).
+               (notes-end-of-defun)
+               (notes-end-of-defun)
+               (setq end-of-note (point))
+               (goto-char beginning-of-note)))
+         (if (re-search-forward (concat "^"
+                                        (if (eq which 'next) "next" "prev")
+                                        ":[ ]+<") end-of-note t)
+             (progn ; link exists, just take it
+               (beginning-of-line)
+               (notes-w3-follow-link (point))
+               (cons (current-buffer) (point)))
+           ;; No link; go through the index file.
+           (if (notes-goto-index-entry which)
+               (let ((index-buffer (current-buffer)))
+                 (notes-index-follow-link (point))
+                 (bury-buffer index-buffer))
+             (error "No known notes in that direction.")
+             (bury-buffer (current-buffer)))
+           (cons (current-buffer) (point))))))
+    ;; Check for going to the same buffer (and the save-excursion
+    ;; undoing our work).
+    (if (eq start-buffer (car end-buffer-and-point))
+       (goto-char (cdr end-buffer-and-point)))))
+       
+
+(defun notes-follow-next-link ()
+  "Go to the next link for this topic."
+  (interactive)
+  (notes-follow-link 'next))
+
+(defun notes-follow-prev-link ()
+  "Go to the previous link for this topic."
+  (interactive)
+  (notes-follow-link 'prev))
+
+(defvar notes-complete-subject-abbrevs-alist
+  '(("SP2010" "USC/Classes/CS551/SP2010")
+    ("FA2011" "USC/Classes/CS551/FA2011"))
+  "notes-complete-subject-abbrevs-alist provides simple substitution of subjects.
+If subject completion is requested, then subject that matches
+the left-side of an alist value is replaced by the right-side value.")
+
+(defun notes-complete-subject-abbrevs (key)
+  "Handle abbreviations on notes SUBJECTS.
+Currently this is just a hack."
+  (let ((value (assoc key notes-complete-subject-abbrevs-alist)))
+    (if value
+       (car (cdr value))
+      key)))
+  
+
+(defun notes-complete-subject ()
+  "Complete the notes subject under point."
+  (interactive)
+  (let
+      ((subject (save-excursion 
+                 (beginning-of-line) 
+                 (notes-extract-subject t)))
+       old-completion-ignore-case
+       full-subject)
+    (if (not (and notes-mode-complete-subjects subject))
+       (call-interactively notes-default-tab-binding)
+      ;; Complete the title.
+      (if (null notes-subject-table)
+         (save-excursion
+           (find-file-noselect (concat notes-dir "/index"))))
+      ;; Do completion.
+      ;; Run completer if it's loaded,
+      ;; otherwise do our own thing.
+      (setq completion-ignore-case t)
+      (cond
+       ((fboundp 'completer-complete-goto)
+       (completer-complete-goto "^ \t\n\"" " " notes-subject-table nil))
+       ;; NEEDSWORK:  should try other completers, too.
+       (t   ;; Do our own completion.
+       (setq full-subject (try-completion subject notes-subject-table)
+             subject (completing-read "Subject: "
+                                      notes-subject-table nil nil 
+                                      (if (stringp full-subject)
+                                          full-subject
+                                        subject)))
+       (delete-region (get-beginning-of-line) (get-end-of-line))
+       (insert "* " (notes-complete-subject-abbrevs subject))))
+       (setq completion-ignore-case old-completion-ignore-case))))
+
+(defun notes-fix-prevnext-this-entry ()
+  "* Fix up the prev link for the current entry,
+if necessary.  Currently this code only handles brand new entries."
+  ;; Contributed from Takashi Nishimoto <g96p0935@mse.waseda.ac.jp>.
+  ;; Thanks!
+  (interactive)
+  (let ((subject (notes-extract-subject nil t))
+        (this-url (notes-current-url))
+        last-url)
+    (save-excursion
+      (set-buffer (find-file-noselect (concat notes-dir "/index")))
+      (goto-char (point-min))
+      (if (re-search-forward
+           (concat "^" (regexp-quote subject) ":.* \\([0-9]+\\)$")
+           (point-max) t) 
+          (save-window-excursion
+            (cond ((and (notes-w3-url
+                         (notes-file-to-url (match-string 1) subject))
+                        (re-search-forward "^next: " nil t)
+                        (looking-at "<none>"))
+                  (let
+                      (pre-modified (buffer-modified-p))
+                    (delete-char 6)
+                    (insert this-url)
+                    (setq last-url (notes-current-url))
+                    (if (and (null pre-modified) 
+                             (>= notes-electric-prevnext 2))
+                        (save-buffer))))))))
+    (if last-url
+       (progn
+         (notes-beginning-of-defun)
+         (forward-line 2)
+         (if (not (looking-at "prev: "))
+             (insert "prev: " last-url "\n" "next: <none>\n\n")
+           (forward-line 3))))))
+
+(defun notes-electric-return (arg)
+  "* Return, underlining if we're on a subject."
+  (interactive "*P")
+  (if (let ((cur-point (point)))
+       (save-excursion
+         (beginning-of-line)
+         (and (not (eq cur-point (point)))  ;; normal return if at b-o-ln
+              (notes-extract-subject t)))) 
+      (progn (notes-underline-line)
+            (if notes-electric-prevnext
+                (notes-fix-prevnext-this-entry)))
+    (call-interactively notes-default-return-binding)))
+
+(defun notes-current-url ()
+  "* Returns the notes-URL of the current entry around the current point."
+  (let ((subject (notes-extract-subject nil t))
+       (date (file-name-nondirectory buffer-file-name)))
+    (concat "<file:///"
+           (abbreviate-file-name buffer-file-name)
+           (if subject (concat "#* " subject) "")
+           ">")))
+
+(defun notes-current-url-as-kill ()
+  "* Put the notes-URL of the current entry into the kill ring."
+  (interactive)
+  (kill-new (notes-current-url)))
+
+(defun notes-goto-index-entry (&optional direction)
+  "* Jump to the index entry corresponding to our current note entry.
+If we're not in an entry, we leave you in the index file.
+If the current date doesn't exist, error in DIRECTION.
+Returns nil if on errors (no index; no date in DIRECTION),
+otherwise the point of the hit."
+  (interactive) 
+  (let ((start-buffer (current-buffer))
+       (subject (notes-extract-subject))  ; get subject if on it
+       (date (if (null (buffer-file-name)) nil 
+               (file-name-nondirectory (buffer-file-name)))))
+    ;; Try and get the subject, either forward...
+    (if (not subject)
+       (save-excursion 
+         (notes-beginning-of-defun)
+         (setq subject (notes-extract-subject))))
+    ;;    ...or backwards.
+    (if (not subject)
+       (save-excursion 
+         (notes-end-of-defun)
+         (setq subject (notes-extract-subject))))
+    ;; Form and jump to the url for the index-entry.
+    (if (and (notes-w3-url (concat notes-url-prefix
+                                  "index"
+                                  (if subject (concat "#" subject) ""))
+                          nil t)
+            ;; Go to the current date, if any.
+            (notes-index-goto-date date direction))
+       t
+      nil)))
+
+(defun notes-extract-subject (&optional relaxed search)
+  "Extract the subject under the point in the current buffer.
+If RELAXED, then accept non-underlined subjects.
+If SEARCH we'll search back in the buffer for the nearest
+subject title.
+
+Returns nil if we're not on as subject."
+  (save-match-data
+    (cond
+     ;; directly on a note
+     ((or (looking-at notes-beginning-of-defun-regexp)
+         (and relaxed
+              (looking-at "^\\* ")))
+      (save-excursion
+       (let
+           ((start (+ (point) 2))
+            (end (progn (end-of-line) (point))))
+         (buffer-substring start end))))
+     (search
+      (save-excursion
+       (notes-beginning-of-defun)
+       (notes-extract-subject relaxed nil)))
+     (t
+      nil))))
+
+
+;;;###autoload
+(defun notes-underline-line ()
+  "* Create a row of dashes as long as this line, or adjust the current underline."
+  (interactive)
+  ;; check to see if it's already underlined
+  (if (save-excursion
+       (forward-line 1)
+       (looking-at "^[ \t]*--*$"))
+      (notes-old-underline-line)
+    (progn
+      (notes-new-underline-line)
+      (insert "\n\n"))))
+
+(defun notes-new-underline-line ()
+  "Underline a line with a row of dashes.  Moves the point after the dashes.
+\\[notes-new-underline-line] reproduces leading spaces."
+  (interactive)
+  (let*
+      ((bol (progn (beginning-of-line)
+                  (point)))
+       (bospaces (progn (skip-chars-forward " \t")
+                       (point)))
+       (nospaces (- bospaces bol))
+       (eol (progn (end-of-line)
+                  (untabify bol (point))
+                  (point))))
+    (insert "\n" (buffer-substring bol bospaces))
+    (insert-char ?- (- eol bospaces))))
+
+(defun notes-old-underline-line ()
+  "Replace the following line with a row of dashes.  Leave the point unchanged."
+  (save-excursion
+    (save-excursion
+      (forward-line 1)
+      (delete-region (get-beginning-of-line) (1+ (get-end-of-line))))
+    (notes-new-underline-line)))
+
+(defun notes-mode-initialize-note-from-cache ()
+  "Build a new note from the cache.  Returns valid cache contents or nil."
+  (save-excursion
+    (let*
+       ((new-buffer (current-buffer))
+        (cache-file (concat notes-dir "/mknew.cache"))
+        (buf (find-file cache-file))
+        magic-line
+        prev-file
+        this-file
+        cache-contents
+        m
+        (result
+         (if (and buf
+                  (>= (count-lines (point-min) (point-max)) 3))
+             (progn
+               ;; If you know a more elegant way to extact the first
+               ;; three lines of a file, please let me know.
+               (goto-char (point-min))
+               (setq m (point))
+               (forward-line 1)
+               (setq magic-line (buffer-substring m (- (point) 1)))
+               (setq m (point))
+               (forward-line 1)
+               (setq prev-file (buffer-substring m (- (point) 1)))
+               (setq m (point))
+               (forward-line 1)
+               (setq this-file (buffer-substring m (- (point) 1)))
+               (setq cache-contents (buffer-substring (point) (point-max)))
+               (bury-buffer buf)
+               ;; is cache valid?
+               (if
+                   (and
+                    (string-equal magic-line "mknew.cache 830494922")
+                    (file-newer-than-file-p cache-file prev-file)
+                    (string-equal (file-name-nondirectory this-file)
+                                  (file-name-nondirectory (buffer-file-name
+                                                           new-buffer))))
+                   cache-contents
+                 nil))
+           nil)))
+      ;; Kill the buffer to avoid "buf changed, reload?" warnings.
+      (if buf
+         (kill-buffer buf))
+      result)))
+
+(defun notes-mode-initialize-note ()
+  "Fill in an empty new note.
+Create any directories as necessary.
+Use the mknew cache if possible."
+  (interactive)
+  (let
+      ((dir (directory-file-name (file-name-directory (buffer-file-name)))))
+    (if (file-exists-p dir)
+       t
+      (make-directory dir t)
+      (message "New intermediate directory created.")))
+  (if notes-mode-initialization-program
+      (let
+         ((cache-contents (notes-mode-initialize-note-from-cache)))
+       (if cache-contents
+           (insert cache-contents)
+         (shell-command-on-region
+          (point-min)
+          (point-max)
+          (concat notes-bin-dir "/" notes-mode-initialization-program " '"
+                  (buffer-file-name) "'") 't)))))
+  
+\f
+;;;
+;;; encryption
+;;; requires "PEM - PGP Enhanced Messaging for GNU Emacs"
+;;; from Roy Frederick Busdiecker, III (Rick)
+;;; or mailcrypt 3.4.x or >=3.5.x
+;;;
+
+(defvar notes-encryption-library 
+  'mailcrypt
+;  (cond
+;   ((fboundp 'mc-encrypt-region) 'mailcrypt)
+;   ((fboundp 'npgp:encrypt-region) 'npgp)
+;   (t nil))
+  "what pgp library to use")
+
+(defvar notes-encryption-sub-library
+  'gpg
+  "what variant of mailcrypt to use ('pgp 'pgp50 'gpg).")
+
+(defvar notes-encryption-npgp-userid nil
+  "PGP key for the current user.")
+
+(defvar notes-encryption-npgp-key-id nil
+  "Keyid of PGP key for the current user.
+Useful if your \\[user-full-name] doesn't match a unique key.
+Should have a leading 0x.")
+
+(defun notes-encryption-npgp-userid ()
+  "Return notes-encryption-userid, initializing it if necessary."
+  (require 'pam)
+  (if (and notes-encryption-userid
+          npgp:*pass-phrases*)
+      notes-encryption-userid
+    (setq notes-encryption-userid
+         (list
+          (if notes-encryption-key-id
+              (npgp:get-key-by-key-id notes-encryption-key-id)
+            (pam:read-name-key (user-full-name)))))))
+
+(defun notes-encryption-mailcrypt-keyid ()
+  "Do the right thing."
+  (require 'mailcrypt)
+  (cond
+   ((eq notes-encryption-sub-library 'pgp)
+    (cdr (mc-pgp-lookup-key mc-pgp-user-id)))
+   ((eq notes-encryption-sub-library 'pgp50)
+    (cdr (mc-pgp50-lookup-key mc-pgp50-user-id)))
+   ((eq notes-encryption-sub-library 'gpg)
+    (cdr (mc-gpg-lookup-key mc-gpg-user-id)))
+   (t (error "notes-encryption-decrypt-region: no pgp sub-library."))))
+
+(defun notes-encryption-load-mailcrypt ()
+  (require 'mailcrypt)
+  ;; ick ick ick this code needs to be cleaned up
+  (cond
+   ((null (eq notes-encryption-library 'mailcrypt))
+    t)
+   ((eq notes-encryption-sub-library 'pgp)
+    (load-library "mc-pgp"))
+   ((eq notes-encryption-sub-library 'pgp50)
+    (load-library "mc-pgp5"))
+   ((eq notes-encryption-sub-library 'gpg)
+    (load-library "mc-gpg"))
+   (t (error "notes-encryption-load-mailcrypt: no pgp sub-library."))))
+
+(defun notes-encryption-decrypt-region (start end)
+  (cond
+   ((eq notes-encryption-library 'npgp)
+    (require 'pam)
+    (require 'npgp)
+    (npgp:decrypt-region start end))
+   ((eq notes-encryption-library 'mailcrypt)
+    (notes-encryption-load-mailcrypt)
+    (cond
+     ((eq notes-encryption-sub-library 'pgp)
+      (mc-pgp-decrypt-region start end))
+     ((eq notes-encryption-sub-library 'pgp50)
+      (mc-pgp50-decrypt-region start end))
+     ((eq notes-encryption-sub-library 'gpg)
+      (mc-gpg-decrypt-region start end))
+     (t (error "notes-encryption-decrypt-region: no pgp sub-library."))))
+   (t (error "notes-encryption-decrypt-region: no pgp library."))))
+
+(defun notes-encryption-encrypt-region (start end)
+  (cond
+   ((eq notes-encryption-library 'npgp)
+    (npgp:encrypt-region (notes-encryption-npgp-userid) start end))
+   ((eq notes-encryption-library 'mailcrypt)
+    (notes-encryption-load-mailcrypt)
+    (let ((old-sign mc-pgp-always-sign)
+         old-comment recipients)
+      (setq mc-pgp-always-sign 'never
+           recipients (list (notes-encryption-mailcrypt-keyid)))
+      (cond
+       ((eq notes-encryption-sub-library 'pgp)
+       (setq old-comment mc-pgp-comment
+             mc-pgp-comment "")
+       (mc-pgp-encrypt-region recipients start end
+                              (notes-encryption-mailcrypt-keyid) nil)
+       (setq mc-pgp-comment old-comment))
+       ((eq notes-encryption-sub-library 'pgp50)
+       (setq old-comment mc-pgp50-comment
+             mc-pgp50-comment "")
+       (mc-pgp50-encrypt-region recipients start end
+                              (notes-encryption-mailcrypt-keyid) nil)
+       (setq mc-pgp50-comment old-comment))
+       ((eq notes-encryption-sub-library 'gpg)
+       (setq old-comment mc-gpg-comment
+             mc-gpg-comment "")
+       (mc-gpg-encrypt-region recipients start end
+                              (notes-encryption-mailcrypt-keyid) nil)
+       (setq mc-gpg-comment old-comment))
+       (t (error "notes-encryption-decrypt-region: no gpg sub-library.")))
+      (setq mc-pgp-always-sign old-sign)))
+   (t (error "notes-encryption-decrypt-region: no pgp library."))))
+
+(defun notes-encrypt-note (prefix)
+  "Encrypt the current note for the current user.  With PREFIX, start from point."
+  (interactive "P")
+  (save-excursion
+    (let (start end)
+      ;; Unless a prefix arg, start at beginning-of-note.
+      (if prefix
+         nil
+       (if (not (looking-at notes-beginning-of-defun-regexp))
+           (notes-beginning-of-defun))
+       ;; skip over the header
+       (while (and (or (looking-at notes-beginning-of-defun-regexp)
+                       (looking-at "^-+$")
+                       (looking-at "^\\(prev\\|next\\): ")
+                       (looking-at "^[ \t]*$"))
+                   (< (point) (point-max)))
+         (forward-line 1)))
+      (setq start (point))
+      ;; sanity check
+      (if (re-search-forward "^-----BEGIN PGP MESSAGE" 
+                            (progn 
+                              (save-excursion 
+                                (notes-end-of-defun) 
+                                (point))) t)
+         (error "Note is already encrypted."))
+      ;; find the end
+      (notes-end-of-defun)
+      (while (or (looking-at notes-beginning-of-defun-regexp)
+                (looking-at "^[ \t]*$"))
+       (forward-line -1))
+      (forward-line 1)
+      (setq end (point))
+      (notes-encryption-encrypt-region start end))))
+
+(defun notes-decrypt-note ()
+  "Decrypt the current note for the current user."
+  (interactive)
+  (save-excursion
+    (if (not (looking-at notes-beginning-of-defun-regexp))
+       (notes-beginning-of-defun))
+    (if (null (re-search-forward "^-----BEGIN PGP" 
+                                (progn 
+                                  (save-excursion 
+                                    (notes-end-of-defun) 
+                                    (point))) t))
+       (error "Note is not encrypted."))
+    (beginning-of-line)
+    (let ((start (point)))
+      (if (null (re-search-forward "^-----END PGP"
+                                  (progn
+                                    (save-excursion
+                                      (notes-end-of-defun)
+                                      (point))) t))
+         (error "Could not find end of encrypted note."))
+      (forward-line)
+      (beginning-of-line)
+      (notes-encryption-decrypt-region start (point)))))
+
+\f
+;;;
+;;; notes or notes-index?
+;;;
+(defun notes-summarize-subject (regexp-subject &optional subject)
+  "* Collect all of a subject."
+  (interactive "P")
+  (require 'notes-index-mode)
+  (if (null subject)
+      (cond
+       ((eq major-mode 'notes-mode)
+       (setq subject (notes-extract-subject nil t)))
+       ((eq major-mode 'notes-index-mode)
+       (setq subject (notes-index-extract-subject)))))
+  (if (null subject)
+   (error "notes-summarize-subject:  no subject specified or inferable."))
+  (let
+      ((buf (get-buffer-create (concat "*notes on " subject "*"))))
+    (pop-to-buffer buf)
+    (erase-buffer)
+    (apply 'call-process (concat notes-bin-dir "/catsubject") nil buf t
+          (if regexp-subject
+              (list "-m" subject)
+            (list subject)))
+    (notes-mode)))
+
+\f
+;;;
+;;; notes-rename-subject
+;;;
+(defun notes-rename-subject ()
+  "* Rename the current subject.
+Assumes working next/prev linkage between the entries."
+  (interactive)
+  (let ((subject (notes-extract-subject)))
+    (condition-case nil
+       (progn
+         (end-of-line)
+         (beginning-of-defun)
+         (if (not (looking-at "* "))
+             (error "confused"))
+         (forward-char 2)
+         (error "not yet done")
+         )
+      (error nil))))
+
+\f
+;;;
+;;; notes-mode
+;;;
+
+;;
+;; This use of define-derived-mode is a crock---maybe
+;; it's better to eval it?
+;; suggestions are welcome.  ---johnh, 26-Oct-98
+;; 
+(if (fboundp 'indented-text-mode)
+    (define-derived-mode notes-mode indented-text-mode "Notes"
+      "See notes-mode-internal for documentation."
+      (notes-mode-internal))
+  (define-derived-mode notes-mode text-mode "Notes"
+      "See notes-mode-internal for documentation."
+    (notes-mode-internal)))
+
+
+(defun notes-mode-internal ()
+  "Enable notes-mode for a buffer.
+
+Inside a notes buffer one can click on URLs and follow them to
+other notes files.
+
+Notes are fontified if notes-use-font-lock is set.
+See the file notes-variables.el for all customization options.
+To change options, (require 'notes-variables) in your .emacs
+and then change things.
+
+Subjects in notes mode are lines beginning with an asterisk
+and underlined with dashes.  Subjects can be completed 
+with \\[notes-complete-subject] and are automatically underlined.
+
+You may wish to add this code to your .emacs file:
+    (setq auto-mode-alist
+       (cons (cons \"/9[0-9][0-9][0-9][0-9][0-9].?$\" 'notes-mode)
+             auto-mode-alist))
+    (define-key global-map \"\C-cn\" 'notes-index-todays-link)
+to automatically enter notes mode.
+
+I have two suggestions for how to organize your notes files.
+First, I collect my notes into a separate file per day.  (If you have
+fewer notes, you may find once-per-week or month more suitable.)
+Second, at the beginning of each file I have a subject \"* Today\".
+Since every file has this subject, I can use its prev and next links
+to easily move around the collection of files.
+
+The key-bindings of this mode are:
+\\{notes-mode-map}"
+  (interactive)  ;; just so documentation can come up
+
+  (notes-platform-init)
+
+  ;; bug workaround:
+  ;; Emacs-19.30's define-derived-mode sets up a bogus syntax-table.
+  ;; (Evidence for the error is ``Wrong type argument: consp, nil''
+  ;; when typing in the buffer.)
+  ;;
+  ;; bug work-around 2:
+  ;; Klaus Zeitler <kzeitler@lucent.com>
+  ;; reports that the next line dies in emacs-21.1 with the error:
+  ;; "Attempt to make a chartable be its own parent".
+  ;; Work-around: more hackery.
+  (if (and (< emacs-major-version 21)
+          (or (>= emacs-major-version 20) (>= emacs-minor-version 30)))
+      (set-syntax-table (setq notes-mode-syntax-table text-mode-syntax-table)))
+
+  ;; now set up the mode
+  (auto-fill-mode 1)
+
+  ;; random key-bindings
+  (define-key notes-mode-map "\M-\C-a" 'notes-beginning-of-defun)
+  (define-key notes-mode-map "\M-\C-e" 'notes-end-of-defun)
+  (define-key notes-mode-map "\C-c\C-d" 'notes-decrypt-note)
+  (define-key notes-mode-map "\C-c\C-e" 'notes-encrypt-note)
+  (define-key notes-mode-map "\C-c\r" 'notes-w3-follow-link)
+  (define-key notes-mode-map "\C-c\C-p" 'notes-follow-prev-link)
+  (define-key notes-mode-map "\C-c\C-n" 'notes-follow-next-link)
+  (define-key notes-mode-map "\C-c\C-i" 'notes-goto-index-entry)
+  (define-key notes-mode-map "\C-c\C-k" 'notes-current-url-as-kill)
+  (define-key notes-mode-map "\C-c\C-s" 'notes-summarize-subject)
+  (define-key notes-mode-map "\C-c-" 'notes-underline-line)
+  (if (null notes-default-tab-binding)
+      (setq notes-default-tab-binding (key-binding "\t")))
+  (define-key notes-mode-map "\t" 'notes-complete-subject)
+  (if (null notes-default-return-binding)
+      (setq notes-default-return-binding (key-binding "\r")))
+  (define-key notes-mode-map "\r" 'notes-electric-return)
+  (define-key notes-mode-map "\n" 'notes-electric-return) ; a more common synonym
+  (notes-platform-bind-mouse notes-mode-map 'S-mouse-2 'notes-w3-follow-link-mouse)
+
+  ;; imenu stuff 
+  (make-variable-buffer-local 'imenu-prev-index-position-function)
+  (make-variable-buffer-local 'imenu-extract-index-name-function)
+  (setq imenu-prev-index-position-function 'notes-beginning-of-defun)
+  (setq imenu-extract-index-name-function 'notes-extract-subject)
+
+  (if notes-use-font-lock
+      (notes-platform-font-lock notes-font-lock-keywords))
+
+  ;; finally, try to fill in an empty note
+  (if (eq (point-min) (point-max))
+      (notes-mode-initialize-note))
+
+  ;; Enable outline-minor-mode (forcebly, in case someone already
+  ;; has it in their text-mode hook).  Bug found by
+  ;; Nils Ackermann <nils@nieback.de>.
+  (if notes-use-outline-mode
+      (outline-minor-mode 1))
+
+  (delay-mode-hooks
+    (run-mode-hooks 'notes-mode-hooks)))
+
+
+
+\f
+;;;
+
+(run-hooks 'notes-mode-load-hooks)
+(provide 'notes-mode)
+