[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
usage-memo.el --- integration of Emacs help system and memo
From: |
rubikitch |
Subject: |
usage-memo.el --- integration of Emacs help system and memo |
Date: |
Mon, 02 Jul 2007 06:00:23 +0900 (JST) |
Hi,
This program enables you to write annotation in *Help* and
third-party help systems. When we do programming, we often use
Emacs help system (ie. describe-function). Do you want to take a
note in the *Help* buffer and want Emacs to show your note later?
In other words, integration of Emacs help and your memo!
Annotation files are stored below ~/memo/umemo by default. Its
subdirectories are categories. And their subdirectories are entry
annotation files. Because annotation files are read in each case,
you can generate annotation files automatically.
;;; usage-memo.el --- integration of Emacs help system and memo
;; $Id: usage-memo.el,v 1.3 2007/07/01 20:05:53 rubikitch Exp $
;; Copyright (C) 2007 rubikitch
;; Author: rubikitch <address@hidden>
;; Keywords: convenience, languages, lisp, help, tools, docs
;; This file 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 file 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., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; This program enables you to write annotation in *Help* and
;; third-party help systems. When we do programming, we often use
;; Emacs help system (ie. describe-function). Do you want to take a
;; note in the *Help* buffer and want Emacs to show your note later?
;; In other words, integration of Emacs help and your memo!
;; Annotation files are stored below ~/memo/umemo by default. Its
;; subdirectories are categories. And their subdirectories are entry
;; annotation files. Because annotation files are read in each case,
;; you can generate annotation files automatically.
;;; Supported help systems:
;; describe-function
;; describe-variable
;; slime-documentation (slime.el)
;; slime-describe-symbol (slime.el)
;; slime-describe-function (slime.el)
;; ri (ri-ruby.el)
;; lh-refe (langhelp / ReFe)
;;
;; usage-memo is general-purpose: it is easy to support other help systems.
;;; Installation:
;; Append to .emacs:
;; (require 'usage-memo)
;; (umemo-initialize)
;; If you support other help systems, add `define-usage-memo' sexps in
;; .emacs or redefine `umemo-initialize'.
;;; Usage:
;; * Switch to *Help*.
;; * Write your annotation below `===*===*===*===*===*===*===*===*===*===*==='
line.
;; * Press C-x C-s to save annotation.
;; * Even if *Help* is killed or Emacs is restarted,
;; your annotation is shown when you look up the same entry!!
;;; Further information:
;; [EVAL IT] (describe-function 'define-usage-memo)
;; [EVAL IT] (describe-function 'usage-memo-mode)
;; [EVAL IT] (describe-variable 'umemo-base-directory)
;; [EVAL IT] (describe-function 'umemo-pathname)
;; [EVAL IT] (describe-variable 'umemo-category)
;; [EVAL IT] (describe-variable 'umemo-entry-name)
;; [EVAL IT] (describe-variable 'umemo-current-entry-name)
;;; History:
;; $Log: usage-memo.el,v $
;; Revision 1.3 2007/07/01 20:05:53 rubikitch
;; Support slime-describe-function.
;; Update docs.
;; First public release!
;;
;; Revision 1.2 2007/07/01 18:40:47 rubikitch
;; write docs.
;;
;; Revision 1.1 2007/07/01 10:07:15 rubikitch
;; Initial revision
;;
;;; Code:
(defvar umemo-base-directory "~/memo/umemo"
"Directory where memo files are placed.
You need not create directory when it does not exist.
usage-memo creates it automatically.")
(defvar umemo-separator "\n===*===*===*===*===*===*===*===*===*===*===\n"
"Separator between documentation and memo.")
(defvar umemo-category nil
"Category of usage-memo. It is defined by `define-usage-memo'.")
(defvar umemo-entry-name nil
"Entry name that help buffer(per buffer) is showing. It is used as filename
of annotation.")
(defvar umemo-current-entry-name nil
"Entry name that help buffer(globally) is showing. See also
`umemo-entry-name'.
It is needed because some help system (eg. SLIME) kills help
buffer and re-create it. In this case, the buffer-local
`umemo-entry-name' is cleared: I have no choice but to use global
variable. But it is probaby rare case.")
(make-variable-buffer-local 'umemo-category)
(make-variable-buffer-local 'umemo-entry-name)
;;;; low-level utils
(defun umemo-pathname (category entry-name)
"Filename of annotation. `umemo-base-directory'/CATEGORY/ENTRY-NAME."
(format "%s/%s/%s" umemo-base-directory category entry-name))
(defun umemo-fall-back-to-global-key-binding-in-memo-area (key)
(let* ((lb (local-key-binding key))
(gb (global-key-binding key)))
(call-interactively
(cond ((umemo-point-is-in-memo-area-p (point)) gb)
(lb lb)
(t gb)))))
(defun umemo-point-is-in-memo-area-p (point)
(save-excursion
(goto-char point)
(search-backward umemo-separator nil t)))
(defmacro umemo-with-append-to-buffer (buffer &rest body)
"Execute BODY at the end of BUFFER."
`(save-excursion
(set-buffer buffer)
(goto-char (point-max))
,@body))
(defmacro umemo-if-buffer-has-separator (&rest body)
`(save-excursion
(goto-char (point-min))
(when (search-forward umemo-separator nil t)
,@body)))
(defun umemo-has-entry-p ()
(save-excursion
(goto-char (point-min))
(and (search-forward umemo-separator nil t)
(/= (point) (point-max)))))
;;;; mid-level utils
(defun umemo-insert-memo (category entry-name buffer)
(let ((path (umemo-pathname category entry-name)))
(umemo-with-append-to-buffer buffer
(setq buffer-read-only nil)
(unless (umemo-has-entry-p)
(insert umemo-separator)
(and (file-exists-p path) (insert-file-contents path))))))
(defun umemo-setup-variables (category entry-name buffer)
(setq umemo-current-entry-name entry-name)
(with-current-buffer buffer
(setq umemo-category category
umemo-entry-name entry-name)))
;;;; initializer
(defun umemo-setup (category entry-name buffer)
(when (get-buffer buffer)
(with-current-buffer buffer
(umemo-setup-variables category entry-name buffer)
(umemo-insert-memo category entry-name buffer)
(usage-memo-mode 1))))
;;;; commands
(defun umemo-save ()
"Save current usage memo(annotation) into file."
(interactive)
(umemo-if-buffer-has-separator
(let* ((path (umemo-pathname umemo-category umemo-entry-name))
(dir (file-name-directory path)))
(unless (file-directory-p dir) (make-directory dir t))
(write-region (point) (point-max) path)
(set-buffer-modified-p nil)
(message "Wrote %s" path))))
(defun umemo-electric-return ()
(interactive)
(umemo-fall-back-to-global-key-binding-in-memo-area "\r"))
;;;; define API
(defmacro define-usage-memo (command category nth-arg buffer-fmt)
"Add usage-memo feature to COMMAND.
Define `usage-memo' around-advice for COMMAND.
CATEGORY is usage-memo category to use, typically language name.
NTH-ARG is COMMAND's argument position (0-origin) representing entry name,
NTH-ARG is passed to `ad-get-arg' macro.
BUFFER-FMT is a `format' string, which %s is replaced with entry name,
representing document display buffer.
For example: To support `describe-function' (already supported):
(define-usage-memo describe-function \"elisp\" 0 \"*Help*\")
Because `define-usage-memo' is a macro, COMMAND is not quoted.
The CATEGORY is \"elisp\". The NTH-ARG is 0 because
`describe-function' takes a symbol to lookup at the first
argument. Because NTH-ARG is 0-origin, 0 means the first
argument. BUFFER-FMT is same as *Help* buffer: it is only
coincidental.
Another example: Support RI lookup (Ruby's document-lookup tool)
`ri' function is defined in ri-ruby.el. The usage is:
(ri ENTRY_NAME)
Then `ri' creates
ri `ENTRY_NAME'
buffer. Instead of reusing a buffer, it creates a buffer per query.
That is why BUFFER-FMT uses `format' string!
(define-usage-memo ri \"ruby\" 0 \"ri `%s'\")
See also `umemo-initialize' definition.
"
`(defadvice ,command (around usage-memo activate)
ad-do-it
(let* ((entry-name (ad-get-arg ,nth-arg))
(buf (with-no-warnings (format ,buffer-fmt entry-name))))
(umemo-setup ,category entry-name buf))))
;; (umemo-initialize)
;; (ri "Array#length")
;; (lh-refe "Array#length")
;; (describe-function 'princ)
;; (slime-documentation "princ")
;; (slime-describe-symbol "princ")
;; (slime-documentation "car")
;;;; sample definition
(defun umemo-initialize ()
"A bunch of `define-usage-memo' definitions. Feel free to redefine!"
(define-usage-memo ri "ruby" 0 "ri `%s'")
(define-usage-memo lh-refe "ruby" 0 "refe \"%s\"")
(define-usage-memo slime-documentation "cl" 0 "*SLIME Description*")
(define-usage-memo slime-describe-symbol "cl" 0 "*SLIME Description*")
(define-usage-memo slime-describe-function "cl" 0 "*SLIME Description*")
(define-usage-memo describe-function "elisp" 0 "*Help*")
(define-usage-memo describe-variable "elisp" 0 "*Help*")
)
;;;; minor mode definition
(defvar usage-memo-mode-map (make-sparse-keymap))
(define-key usage-memo-mode-map "\C-x\C-s" 'umemo-save)
(define-key usage-memo-mode-map "\r" 'umemo-electric-return)
(define-minor-mode usage-memo-mode
"Automatically enabled minor mode to add usage-memo feature by
`define-usage-memo'.
Write your annotation below `===*===*===*===*===*===*===*===*===*===*===' line.
\\<usage-memo-mode-map>\\[umemo-save]: Save your annotation to file indicated
by `umemo-pathname'.
Of course, your annotation is revived even if Emacs is restarted!
"
nil "<UMemo>" usage-memo-mode-map
:global nil
(setq buffer-read-only nil)
(when view-mode (view-mode -1))
(buffer-enable-undo))
;;;; SLIME hack
(defadvice slime-show-description (after usage-memo-aux activate)
"usage-memo hack."
(when umemo-current-entry-name
(umemo-setup "cl" umemo-current-entry-name "*SLIME Description*")))
;; (progn (ad-disable-advice 'slime-show-description 'around 'usage-memo)
(ad-update 'slime-show-description))
(provide 'usage-memo)
;; How to save (DO NOT REMOVE!!)
;; (let ((oddmuse-wiki "EmacsWiki")(oddmuse-page-name "usage-memo.el"))
(call-interactively 'oddmuse-post))
;;; usage-memo.el ends here
--
rubikitch
http://www.rubyist.net/~rubikitch/
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- usage-memo.el --- integration of Emacs help system and memo,
rubikitch <=