2007年6月22日星期五

msf-abbrev.el

msf-abbrev.el

msf-abbrev.el

Intro/Demo

A package to manage many mode-specific abbrevs. At least, it started out that way. Now it seems to have evolved into a way to make certain programming tasks as easy as filling out forms. The best way to see how it works is watch the demo. (Feel free to use this demo wherever, however, you like, for any personal or professional purposes; consider it in the public domain). In the demo, I use the TAB key to navigate between fields, and the space bar to trigger expansion of the abbrevs after typing the abbrev name. For more info on abbrevs, look up the relevant Emacs documentation (look for abbrevs, not dynamic abbrevs). To those who are curious, I used the x11record script to create this demo.

NOTE: I am aware of packages such as ELSE, tempo, skeleton, some of which do similar things. However, I believe this package does some things better than these other packages, but you'll have to decide for yourself. I tend to name my abbrev's ending in "x", as you can tell if you watched the demo; this is merely my convention. Each abbrev is put in a file, in a special directory, which names the mode. The parent directory of the directories containing a bunch of directories naming each mode is loaded using the command (e.g.):

(msf-abbrev-load-tree "~/emacs/mode-abbrevs")

where my ~/emacs/mode-abbrevs dir looks like:
 drwx------   2 brutt brutt 4096 May  9 15:00 LaTeX-mode
drwx------ 2 brutt brutt 4096 May 9 15:00 TeX-mode
drwx------ 2 brutt brutt 4096 Jun 5 12:42 c++-mode
drwx------ 2 brutt brutt 4096 Jun 5 12:19 c-mode
drwx------ 2 brutt brutt 4096 Sep 16 2004 cperl-mode
drwx------ 2 brutt brutt 4096 Oct 6 2004 global
drwx------ 2 brutt brutt 4096 Oct 6 2004 java-mode
drwx------ 2 brutt brutt 4096 Oct 6 2004 jde-mode
drwx------ 2 brutt brutt 4096 Sep 16 2004 perl-mode
drwx------ 2 brutt brutt 4096 Jun 3 17:25 python-mode
drwx------ 2 brutt brutt 4096 Jun 3 17:25 sh-mode
drwx------ 2 brutt brutt 4096 Jun 3 17:25 shell-mode
and my ~/emacs/mode-abbrevs/c++-mode dir looks like:
 /home/brutt/emacs/mode-abbrevs/c++-mode:
total used in directory 424 available 4092320
drwx------ 2 brutt brutt 4096 Jun 5 12:42 .
drwx------ 13 brutt brutt 4096 Mar 30 14:04 ..
-rw------- 1 brutt brutt 207 Jun 5 12:19 fclosex
-rw------- 1 brutt brutt 244 Jun 5 12:19 fopenx
-rw------- 1 brutt brutt 259 Jun 5 12:19 fwritex
...
This scheme makes it really easy to add new abbrevs that are active in certain modes, or modify them without writing elisp to do so. I think this makes abbrevs more useful. Each abbrev file expands with a special syntax, enabling tasks such as user input via the minibuffer, filling out "forms" (navigating using the TAB key) and leaving the cursor at a specific place. Somewhat of a cross between a form widget toolkit and using skeletons.

File Syntax

By default, the file contents will be inserted. However, the following special forms are recognized:
    <cursor> leaves the cursor there at the end

<varlookup "user-mail-address"> inserts the elisp value of the expression in quotes

<elisp "(insert (current-time-string))"> executes a snippet of elisp at that point in the file

<query "what color? "> asks the user "what color?" and replaces with the response. Any question can be
asked here and will be prompted in the minibuffer. Multiple <query "what color? ">
terms will result in a single question but multiple identical replacements.

<field "foo"> <-- creates a "form" field called foo, which can be
TAB-navigated and shift-TAB-navigated

<choose><choice "foo"><choice "bar"></choose> creates a combo box, press enter and then
arrow keys to make a choice

<endpoint> marks the end of a form (i.e. the last point to TAB to) of a set of "field" or "choose" tags

<comment "blah blah"> will be removed altogether
As an example, here is my abbrev file fopenx for the 'fopen' C library command:
    if ((f = fopen(<field "char * filename">, <choose><choice ""r""><choice ""w""><choice ""a""><choice ""r+""></choose>)) == NULL)
{
std::cerr << "ERROR: opening file"
<< " at " << __FILE__ << ":" << __LINE__
<< std::endl << std::flush;
exit(1);
}
<endpoint>
Also, if you name your file 'fopenx.el' instead of 'fopenx', then the file will be assumed to be an elisp file which will be evaluated to do arbitrary things (like inserting current date, etc.), instead of the contents being inserted directly.

Finally, if you (e.g.) have a file 'fwritex_' in addition to 'fwrite', the underscore-trailing file can be used to transform the expansion depending on current in-buffer context (e.g. as provided by semantic/cedet). Look at my 'fwritex_' for an example.

Symlinks

Symlinks can be used to link together mode directories (i.e. c-mode, c++-mode, etc.) if that is your liking. However, they don't work on Windows. So the following solution is now implemented. (Feel free to keep using symlinks however if you're only on unix platforms). Create empty ".aliases." files as follows instead of symlinks, to indicate what aliases what. i.e. if mode B should use mode A's abbrevs, create empty file "B-mode.aliases.A-mode" in the mode-abbrevs directory. More use of the filesystem-as-data-structure. :)
      $ ls -al ~/emacs/mode-abbrevs
total 72
drwx------ 2 rutt rutt 4096 Jun 15 09:56 LaTeX-mode
-rw-rw---- 1 rutt rutt 0 Aug 9 09:12 TeX-mode.aliases.LaTeX-mode
-rw-rw---- 1 rutt rutt 0 Aug 9 08:45 c++- mode.aliases.c-mode
drwx------ 2 rutt rutt 28672 Jul 3 13:45 c-mode
-rw-rw---- 1 rutt rutt 0 Aug 9 09:12 cperl-mode.aliases.perl-mode
drwxrwx--- 2 rutt rutt 4096 May 17 15:10 emacs-lisp-mode
drwxrwx--- 2 rutt rutt 4096 Jul 13 2005 fortran-mode
drwxrwx--- 2 rutt rutt 4096 Aug 9 08:24 global
drwx------ 2 rutt rutt 4096 Jul 26 07:52 java-mode
-rw-rw---- 1 rutt rutt 0 Aug 9 09:13 jde-mode.aliases.java-mode
drwxrwx--- 2 rutt rutt 4096 Sep 18 2005 lisp-interaction-mode
drwxrwx--- 2 rutt rutt 4096 Jun 20 08:45 message-mode
drwx------ 2 rutt rutt 4096 Jul 13 2005 perl-mode
drwx------ 2 rutt rutt 4096 Aug 8 14:46 python-mode
drwx------ 2 rutt rutt 4096 May 24 16:49 sh-mode
drwx------ 2 rutt rutt 4096 Jul 13 2005 shell-mode

Requirements

GNU Emacs 22 (or a emacs from CVS from 2005 or later) is required. Emacs 21.3 is known not to work.
Concerning XEmacs, although it earlier was reported that it works, I find that it does not; the low-level details of text properties are too different between the two versions that I cannot support XEmacs at this time.

Downloads

msf-abbrev.el 1.0beta3

My own abbrev definitions version 1.0beta3, for example purposes (updated on Wed Aug 9 2006)

Usage

Initialization is somewhat of a problem, as all modes needed in the abbrevs you define must be loaded before msf-abbrev loading is done. I hope to fix this somehow. But for now, I initialize like the following.
First, place msf-abbrev.el in your load-path. e.g. in your ~/.emacs:
(add-to-list 'load-path "~/directory/where/you/downloaded/msf-abbrev.el/file")
Then, I do the following in my ~/.emacs:
;; ensure abbrev mode is always on
(setq-default abbrev-mode t)

;; do not bug me about saving my abbreviations
(setq save-abbrevs nil)

;; load up modes I use
(require 'cc-mode)
(require 'perl-mode)
(require 'cperl-mode)
(require 'sh-script)
(require 'shell)
(require 'tex-site) ;; I use AUCTeX
(require 'latex) ;; needed to define LaTeX-mode-hook under AUCTeX
(require 'tex) ;; needed to define TeX-mode-hook under AUCTeX
;; (require 'python) ;; I use python.el from Emacs CVS, uncomment if you do also

;; load up abbrevs for these modes
(require 'msf-abbrev)
(setq msf-abbrev-verbose t) ;; optional
(setq msf-abbrev-root "~/emacs/mode-abbrevs")
(global-set-key (kbd "C-c l") 'msf-abbrev-goto-root)
(global-set-key (kbd "C-c a") 'msf-abbrev-define-new-abbrev-this-mode)
(msf-abbrev-load)
Whenever I define a new abbrev, it is loaded automatically when I save the file, thanks to an after-save-hook. To define a new abbrev in a mode, I just do C-c a and it will prompt me for the abbrev name (as seen in the demo). The whole process is now streamlined (compared to previous versions). (NOTE: for modes which do not have an abbreviation table (such as emacs-lisp-mode or AUCTeX), after defining a new abbrev, you still need to restart Emacs or re-visit any of the open files in that mode to cause the changes to take effect).

User-Contributed abbrevs

In case you come up with some abbreviations you think are useful, send them to me and I will post them here.

Nickolay Savchenko has contributed some c-mode abbrevs by parsing glibc function index ('info glibc'). This should contain most of the C library functions. The actual abbrevs (with c-mode directory) are available here and the index of functions he used to build these abbrevs is available here. Thanks Nickolay! I have integrated some of his functions into my own abbrev files (I eliminated those files containing '_' as abbrevs in emacs cannot contain a '_').

Known bugs

  • some people have problems with large unrelated-to-msf-abbrev yanks (since this package defadvices yank). if you can reproduce this, let me know. I believe it's now fixed in version 1.0beta1, but would like to hear counterexamples.
  • Sometimes, the logic to ressurect a deleted form field breaks when the whole form is deleted, and then new text is inserted in its place; the symptom of this is that you get highlighted text where you did not expect it, while inputting new text. If this happens, you should be able to eliminate the form entirely with the key binding M-RET while on a highlighted field. This key binding is active normally anyway, but usually only needed when this particular bug shows up.
  • One Mac user had success using this package with Carbon Emacs but under Aquamacs (a different Mac OS X port) the LaTeX-mode (AUCTeX) abbrevs didn't load while the other modes did. The user reported the following solution:
    The problem is associated with HFS+ (the Mac OS X filesystem).
    It doesn't handle case (!!!). All the unix tools on Mac OS X
    do so you don't really notice (tab-completion with bash is
    case-sensitive but trying to create two files whose names only
    differ in case fails).

    So now I renamed all the mode-dirs to the proper lowercase version
    and now it works. Weird, though, because opening "LaTeX-mode" should
    find "latex-mode" as well if the file system is not case sensitive.

Bug Reports/Comments

Send these to rutt.4 AT osu.edu (include "msf-abbrev" in the subject). NOTE: my old email address was deactivated sometime in early 2007, so I'm sorry if you sent mail to me which bounced, please try again now with the above.

1 条评论:

Unknown 说...

"opening "LaTeX-mode" should
find "latex-mode" as well if the file system is not case sensitive"


That user should read up on autoloading. M-x LaTeX-mode does NOT automatically look for a file called latex-mode.el or LaTeX-mode.el