From 16377edfab36556ff212eecb646aa8b21da16350 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Mon, 4 Nov 2013 11:25:22 +0100 Subject: [PATCH 1/1] initial commit. --- ac-dict/cfengine3-mode | 36 + centered-cursor-mode.el | 421 + centered-cursor-mode.elc | Bin 0 -> 13519 bytes cfengine-code-style.el | 58 + cfengine-code-style.elc | Bin 0 -> 1272 bytes cfengine.el | 613 + cfengine.elc | Bin 0 -> 17186 bytes custom.el | 22 + egg-grep.el | 132 + egg-grep.elc | Bin 0 -> 5862 bytes egg.el | 6208 ++++++++ egg.elc | Bin 0 -> 279833 bytes init.el | 320 + template.el | 2609 ++++ template.elc | Bin 0 -> 82069 bytes templates/DEFAULT.tpl | 3 + templates/Makefile.tpl | 9 + templates/README.tpl | 11 + templates/TEMPLATE.c.tpl | 7 + templates/TEMPLATE.cls.tpl | 47 + templates/TEMPLATE.el.tpl | 47 + templates/TEMPLATE.h.tpl | 10 + templates/TEMPLATE.html.tpl | 21 + templates/TEMPLATE.java.tpl | 16 + templates/TEMPLATE.pl.tpl | 48 + templates/TEMPLATE.sh.tpl | 2 + templates/TEMPLATE.sty.tpl | 43 + templates/TEMPLATE.tex.tpl | 24 + xemacs-bg.xpm | 38 + xemacs-packages/etc/bbdb/bbdb-213-310.el | 57 + xemacs-packages/etc/bbdb/bbdb-415-510.el | 87 + .../etc/bbdb/bbdb-areacode-split.pl | 62 + xemacs-packages/etc/bbdb/bbdb-cid.pl | 516 + xemacs-packages/etc/bbdb/bbdb-srv.pl | 45 + xemacs-packages/etc/bbdb/bbdb-to-netscape.el | 213 + xemacs-packages/etc/bbdb/bbdb-unlazy-lock.pl | 19 + xemacs-packages/etc/bbdb/tex/bbdb-cols.tex | 234 + .../etc/bbdb/tex/bbdb-print-brief.tex | 159 + xemacs-packages/etc/bbdb/tex/bbdb-print.tex | 171 + xemacs-packages/etc/ediff/ediff-A-up.xbm | 6 + xemacs-packages/etc/ediff/ediff-A-up.xpm | 24 + xemacs-packages/etc/ediff/ediff-A-xx.xpm | 24 + xemacs-packages/etc/ediff/ediff-B-up.xbm | 6 + xemacs-packages/etc/ediff/ediff-B-up.xpm | 25 + xemacs-packages/etc/ediff/ediff-B-xx.xpm | 25 + xemacs-packages/etc/ediff/ediff-help.xbm | 6 + xemacs-packages/etc/ediff/ediff-help.xpm | 26 + xemacs-packages/etc/ediff/ediff-next.xbm | 6 + xemacs-packages/etc/ediff/ediff-next.xpm | 25 + xemacs-packages/etc/ediff/ediff-prev.xbm | 6 + xemacs-packages/etc/ediff/ediff-prev.xpm | 23 + xemacs-packages/etc/ediff/ediff-quit.xbm | 6 + xemacs-packages/etc/ediff/ediff-quit.xpm | 26 + xemacs-packages/etc/ediff/ediff-refine.xbm | 6 + xemacs-packages/etc/ediff/ediff-refine.xpm | 24 + xemacs-packages/etc/ediff/ediff-save-xx.xbm | 6 + xemacs-packages/etc/ediff/ediff-save-xx.xpm | 25 + xemacs-packages/etc/ediff/ediff-save.xbm | 6 + xemacs-packages/etc/ediff/ediff-save.xpm | 25 + .../etc/ediff/ediff-toggle-split-up.xbm | 6 + .../etc/ediff/ediff-toggle-split-up.xpm | 25 + xemacs-packages/etc/ediff/ediff-update.xbm | 6 + xemacs-packages/etc/ediff/ediff-update.xpm | 25 + xemacs-packages/etc/enriched.doc | 219 + .../etc/python-modes/pydoc_lisp.py | 113 + xemacs-packages/info/bbdb.info | 3626 +++++ xemacs-packages/info/ediff.info | 2668 ++++ xemacs-packages/info/edit-utils.info | 3987 ++++++ xemacs-packages/info/os-utils.info | 849 ++ xemacs-packages/info/patcher.info | 1887 +++ xemacs-packages/info/pgg.info | 431 + xemacs-packages/info/prog-modes.info | 2718 ++++ xemacs-packages/info/re-builder.info | 207 + xemacs-packages/info/smtpmail.info | 414 + xemacs-packages/info/speedbar.info | 1318 ++ xemacs-packages/info/tempo.info | 588 + xemacs-packages/info/tramp.info | 2114 +++ xemacs-packages/info/tramp_ja.info | 2043 +++ xemacs-packages/lisp/bbdb/ChangeLog | 1140 ++ xemacs-packages/lisp/bbdb/INSTALL | 166 + xemacs-packages/lisp/bbdb/README | 1 + xemacs-packages/lisp/bbdb/_pkg.el | 5 + xemacs-packages/lisp/bbdb/auto-autoloads.el | 764 + xemacs-packages/lisp/bbdb/auto-autoloads.elc | Bin 0 -> 35864 bytes xemacs-packages/lisp/bbdb/bbdb-com.el | 3612 +++++ xemacs-packages/lisp/bbdb/bbdb-com.elc | Bin 0 -> 94423 bytes xemacs-packages/lisp/bbdb/bbdb-ftp.el | 202 + xemacs-packages/lisp/bbdb/bbdb-ftp.elc | Bin 0 -> 4986 bytes xemacs-packages/lisp/bbdb/bbdb-gnus.el | 814 ++ xemacs-packages/lisp/bbdb/bbdb-gnus.elc | Bin 0 -> 24500 bytes xemacs-packages/lisp/bbdb/bbdb-gui.el | 526 + xemacs-packages/lisp/bbdb/bbdb-gui.elc | Bin 0 -> 9745 bytes xemacs-packages/lisp/bbdb/bbdb-hooks.el | 710 + xemacs-packages/lisp/bbdb/bbdb-hooks.elc | Bin 0 -> 15930 bytes xemacs-packages/lisp/bbdb/bbdb-merge.el | 261 + xemacs-packages/lisp/bbdb/bbdb-merge.elc | Bin 0 -> 5424 bytes xemacs-packages/lisp/bbdb/bbdb-mhe.el | 227 + xemacs-packages/lisp/bbdb/bbdb-mhe.elc | Bin 0 -> 5450 bytes xemacs-packages/lisp/bbdb/bbdb-migrate.el | 486 + xemacs-packages/lisp/bbdb/bbdb-migrate.elc | Bin 0 -> 9727 bytes xemacs-packages/lisp/bbdb/bbdb-print.el | 734 + xemacs-packages/lisp/bbdb/bbdb-print.elc | Bin 0 -> 17833 bytes xemacs-packages/lisp/bbdb/bbdb-reportmail.el | 111 + xemacs-packages/lisp/bbdb/bbdb-reportmail.elc | Bin 0 -> 2686 bytes xemacs-packages/lisp/bbdb/bbdb-rmail.el | 179 + xemacs-packages/lisp/bbdb/bbdb-rmail.elc | Bin 0 -> 4417 bytes xemacs-packages/lisp/bbdb/bbdb-sc.el | 211 + xemacs-packages/lisp/bbdb/bbdb-sc.elc | Bin 0 -> 6051 bytes xemacs-packages/lisp/bbdb/bbdb-snarf.el | 631 + xemacs-packages/lisp/bbdb/bbdb-snarf.elc | Bin 0 -> 11932 bytes xemacs-packages/lisp/bbdb/bbdb-srv.el | 288 + xemacs-packages/lisp/bbdb/bbdb-srv.elc | Bin 0 -> 6882 bytes xemacs-packages/lisp/bbdb/bbdb-vm.el | 432 + xemacs-packages/lisp/bbdb/bbdb-vm.elc | Bin 0 -> 12205 bytes xemacs-packages/lisp/bbdb/bbdb-w3.el | 63 + xemacs-packages/lisp/bbdb/bbdb-w3.elc | Bin 0 -> 1708 bytes xemacs-packages/lisp/bbdb/bbdb-whois.el | 263 + xemacs-packages/lisp/bbdb/bbdb-whois.elc | Bin 0 -> 3841 bytes xemacs-packages/lisp/bbdb/bbdb-xemacs.el | 113 + xemacs-packages/lisp/bbdb/bbdb-xemacs.elc | Bin 0 -> 2501 bytes xemacs-packages/lisp/bbdb/bbdb.el | 3749 +++++ xemacs-packages/lisp/bbdb/bbdb.elc | Bin 0 -> 96928 bytes xemacs-packages/lisp/bbdb/custom-load.el | 31 + xemacs-packages/lisp/bbdb/custom-load.elc | Bin 0 -> 1630 bytes xemacs-packages/lisp/c-support/ChangeLog | 97 + xemacs-packages/lisp/c-support/_pkg.el | 5 + .../lisp/c-support/auto-autoloads.el | 252 + .../lisp/c-support/auto-autoloads.elc | Bin 0 -> 9852 bytes .../lisp/c-support/c-comment-edit.el | 323 + .../lisp/c-support/c-comment-edit.elc | Bin 0 -> 7156 bytes xemacs-packages/lisp/c-support/c-fill.el | 272 + xemacs-packages/lisp/c-support/c-fill.elc | Bin 0 -> 3609 bytes xemacs-packages/lisp/c-support/c-style.el | 199 + xemacs-packages/lisp/c-support/c-style.elc | Bin 0 -> 3205 bytes xemacs-packages/lisp/c-support/cmacexp.el | 389 + xemacs-packages/lisp/c-support/cmacexp.elc | Bin 0 -> 5342 bytes xemacs-packages/lisp/c-support/ctypes.el | 1737 +++ xemacs-packages/lisp/c-support/ctypes.elc | Bin 0 -> 32444 bytes xemacs-packages/lisp/c-support/custom-load.el | 13 + .../lisp/c-support/custom-load.elc | Bin 0 -> 809 bytes xemacs-packages/lisp/c-support/hideif.el | 1081 ++ xemacs-packages/lisp/c-support/hideif.elc | Bin 0 -> 19469 bytes xemacs-packages/lisp/c-support/hideshow.el | 933 ++ xemacs-packages/lisp/c-support/hideshow.elc | Bin 0 -> 19130 bytes xemacs-packages/lisp/ecrypto/ChangeLog | 243 + xemacs-packages/lisp/ecrypto/_pkg.el | 5 + xemacs-packages/lisp/ecrypto/ascii-armor.el | 138 + xemacs-packages/lisp/ecrypto/ascii-armor.elc | Bin 0 -> 2268 bytes .../lisp/ecrypto/auto-autoloads.el | 49 + .../lisp/ecrypto/auto-autoloads.elc | Bin 0 -> 1779 bytes xemacs-packages/lisp/ecrypto/blowfish.el | 482 + xemacs-packages/lisp/ecrypto/blowfish.elc | Bin 0 -> 18535 bytes xemacs-packages/lisp/ecrypto/custom-load.el | 14 + xemacs-packages/lisp/ecrypto/custom-load.elc | Bin 0 -> 837 bytes xemacs-packages/lisp/ecrypto/des.el | 330 + xemacs-packages/lisp/ecrypto/des.elc | Bin 0 -> 8486 bytes xemacs-packages/lisp/ecrypto/encrypt.el | 273 + xemacs-packages/lisp/ecrypto/encrypt.elc | Bin 0 -> 6743 bytes xemacs-packages/lisp/ecrypto/hex-util.el | 75 + xemacs-packages/lisp/ecrypto/hex-util.elc | Bin 0 -> 1233 bytes xemacs-packages/lisp/ecrypto/md4.el | 230 + xemacs-packages/lisp/ecrypto/md4.elc | Bin 0 -> 7135 bytes xemacs-packages/lisp/ecrypto/md5-dl.el | 55 + xemacs-packages/lisp/ecrypto/md5-dl.elc | Bin 0 -> 1234 bytes xemacs-packages/lisp/ecrypto/md5-el.el | 411 + xemacs-packages/lisp/ecrypto/md5-el.elc | Bin 0 -> 10233 bytes xemacs-packages/lisp/ecrypto/md5.el | 79 + xemacs-packages/lisp/ecrypto/md5.elc | Bin 0 -> 867 bytes xemacs-packages/lisp/ecrypto/paranoid.el | 87 + xemacs-packages/lisp/ecrypto/paranoid.elc | Bin 0 -> 1626 bytes xemacs-packages/lisp/ecrypto/password.el | 192 + xemacs-packages/lisp/ecrypto/password.elc | Bin 0 -> 4266 bytes xemacs-packages/lisp/ecrypto/rander.el | 137 + xemacs-packages/lisp/ecrypto/rander.elc | Bin 0 -> 2908 bytes xemacs-packages/lisp/ecrypto/rc16.el | 122 + xemacs-packages/lisp/ecrypto/rc16.elc | Bin 0 -> 2917 bytes xemacs-packages/lisp/ecrypto/rijndael.el | 843 ++ xemacs-packages/lisp/ecrypto/rijndael.elc | Bin 0 -> 19107 bytes xemacs-packages/lisp/ecrypto/sha1.el | 442 + xemacs-packages/lisp/ecrypto/sha1.elc | Bin 0 -> 6428 bytes xemacs-packages/lisp/ediff/ChangeLog | 907 ++ xemacs-packages/lisp/ediff/README | 70 + xemacs-packages/lisp/ediff/_pkg.el | 5 + xemacs-packages/lisp/ediff/auto-autoloads.el | 230 + xemacs-packages/lisp/ediff/auto-autoloads.elc | Bin 0 -> 11790 bytes xemacs-packages/lisp/ediff/custom-load.el | 18 + xemacs-packages/lisp/ediff/custom-load.elc | Bin 0 -> 1085 bytes xemacs-packages/lisp/ediff/ediff-diff.el | 1559 ++ xemacs-packages/lisp/ediff/ediff-diff.elc | Bin 0 -> 29203 bytes xemacs-packages/lisp/ediff/ediff-help.el | 332 + xemacs-packages/lisp/ediff/ediff-help.elc | Bin 0 -> 10363 bytes xemacs-packages/lisp/ediff/ediff-hook.el | 376 + xemacs-packages/lisp/ediff/ediff-hook.elc | Bin 0 -> 5442 bytes xemacs-packages/lisp/ediff/ediff-init.el | 1882 +++ xemacs-packages/lisp/ediff/ediff-init.elc | Bin 0 -> 63784 bytes xemacs-packages/lisp/ediff/ediff-merg.el | 402 + xemacs-packages/lisp/ediff/ediff-merg.elc | Bin 0 -> 9249 bytes xemacs-packages/lisp/ediff/ediff-mult.el | 2396 ++++ xemacs-packages/lisp/ediff/ediff-mult.elc | Bin 0 -> 50192 bytes xemacs-packages/lisp/ediff/ediff-ptch.el | 856 ++ xemacs-packages/lisp/ediff/ediff-ptch.elc | Bin 0 -> 15503 bytes xemacs-packages/lisp/ediff/ediff-tbar.el | 377 + xemacs-packages/lisp/ediff/ediff-tbar.elc | Bin 0 -> 9548 bytes xemacs-packages/lisp/ediff/ediff-util.el | 4315 ++++++ xemacs-packages/lisp/ediff/ediff-util.elc | Bin 0 -> 93703 bytes xemacs-packages/lisp/ediff/ediff-vers.el | 322 + xemacs-packages/lisp/ediff/ediff-vers.elc | Bin 0 -> 5133 bytes xemacs-packages/lisp/ediff/ediff-wind.el | 1326 ++ xemacs-packages/lisp/ediff/ediff-wind.elc | Bin 0 -> 24724 bytes xemacs-packages/lisp/ediff/ediff.el | 1546 ++ xemacs-packages/lisp/ediff/ediff.elc | Bin 0 -> 33888 bytes xemacs-packages/lisp/edit-utils/ChangeLog | 1756 +++ xemacs-packages/lisp/edit-utils/_pkg.el | 5 + xemacs-packages/lisp/edit-utils/abbrevlist.el | 55 + .../lisp/edit-utils/abbrevlist.elc | Bin 0 -> 1038 bytes .../lisp/edit-utils/after-save-commands.el | 407 + .../lisp/edit-utils/after-save-commands.elc | Bin 0 -> 8687 bytes xemacs-packages/lisp/edit-utils/align.el | 1591 +++ xemacs-packages/lisp/edit-utils/align.elc | Bin 0 -> 36885 bytes xemacs-packages/lisp/edit-utils/allout.el | 4773 +++++++ xemacs-packages/lisp/edit-utils/allout.elc | Bin 0 -> 117101 bytes xemacs-packages/lisp/edit-utils/array.el | 951 ++ xemacs-packages/lisp/edit-utils/array.elc | Bin 0 -> 22949 bytes .../lisp/edit-utils/atomic-extents.el | 110 + .../lisp/edit-utils/atomic-extents.elc | Bin 0 -> 1598 bytes .../lisp/edit-utils/auto-autoloads.el | 1563 ++ .../lisp/edit-utils/auto-autoloads.elc | Bin 0 -> 67223 bytes xemacs-packages/lisp/edit-utils/autorevert.el | 375 + .../lisp/edit-utils/autorevert.elc | Bin 0 -> 8028 bytes xemacs-packages/lisp/edit-utils/avoid.el | 407 + xemacs-packages/lisp/edit-utils/avoid.elc | Bin 0 -> 9386 bytes xemacs-packages/lisp/edit-utils/backup-dir.el | 576 + .../lisp/edit-utils/backup-dir.elc | Bin 0 -> 8304 bytes .../lisp/edit-utils/balloon-help.el | 602 + .../lisp/edit-utils/balloon-help.elc | Bin 0 -> 14801 bytes .../lisp/edit-utils/big-menubar.el | 215 + .../lisp/edit-utils/big-menubar.elc | Bin 0 -> 5331 bytes .../lisp/edit-utils/blink-cursor.el | 139 + .../lisp/edit-utils/blink-cursor.elc | Bin 0 -> 3073 bytes .../lisp/edit-utils/blink-paren.el | 181 + .../lisp/edit-utils/blink-paren.elc | Bin 0 -> 3449 bytes xemacs-packages/lisp/edit-utils/bookmark.el | 2305 +++ xemacs-packages/lisp/edit-utils/bookmark.elc | Bin 0 -> 52555 bytes xemacs-packages/lisp/edit-utils/compare-w.el | 180 + xemacs-packages/lisp/edit-utils/compare-w.elc | Bin 0 -> 2993 bytes xemacs-packages/lisp/edit-utils/completion.el | 2727 ++++ .../lisp/edit-utils/completion.elc | Bin 0 -> 37744 bytes xemacs-packages/lisp/edit-utils/crm.el | 633 + xemacs-packages/lisp/edit-utils/crm.elc | Bin 0 -> 12468 bytes .../lisp/edit-utils/custom-load.el | 69 + .../lisp/edit-utils/custom-load.elc | Bin 0 -> 2928 bytes xemacs-packages/lisp/edit-utils/dabbrev.el | 1060 ++ xemacs-packages/lisp/edit-utils/dabbrev.elc | Bin 0 -> 21123 bytes xemacs-packages/lisp/edit-utils/desktop.el | 801 ++ xemacs-packages/lisp/edit-utils/desktop.elc | Bin 0 -> 16915 bytes .../lisp/edit-utils/detached-minibuf.el | 169 + .../lisp/edit-utils/detached-minibuf.elc | Bin 0 -> 3291 bytes xemacs-packages/lisp/edit-utils/edit-faces.el | 373 + .../lisp/edit-utils/edit-faces.elc | Bin 0 -> 9391 bytes .../lisp/edit-utils/edit-toolbar.el | 547 + .../lisp/edit-utils/edit-toolbar.elc | Bin 0 -> 14892 bytes xemacs-packages/lisp/edit-utils/fast-lock.el | 773 + xemacs-packages/lisp/edit-utils/fast-lock.elc | Bin 0 -> 15738 bytes xemacs-packages/lisp/edit-utils/file-part.el | 273 + xemacs-packages/lisp/edit-utils/file-part.elc | Bin 0 -> 7451 bytes .../lisp/edit-utils/floating-toolbar.el | 385 + .../lisp/edit-utils/floating-toolbar.elc | Bin 0 -> 7909 bytes xemacs-packages/lisp/edit-utils/flow-ctrl.el | 120 + xemacs-packages/lisp/edit-utils/flow-ctrl.elc | Bin 0 -> 2283 bytes xemacs-packages/lisp/edit-utils/foldout.el | 581 + xemacs-packages/lisp/edit-utils/foldout.elc | Bin 0 -> 6084 bytes xemacs-packages/lisp/edit-utils/func-menu.el | 2757 ++++ xemacs-packages/lisp/edit-utils/func-menu.elc | Bin 0 -> 56302 bytes xemacs-packages/lisp/edit-utils/highline.el | 882 ++ xemacs-packages/lisp/edit-utils/highline.elc | Bin 0 -> 14806 bytes xemacs-packages/lisp/edit-utils/hippie-exp.el | 1129 ++ .../lisp/edit-utils/hippie-exp.elc | Bin 0 -> 18590 bytes xemacs-packages/lisp/edit-utils/icomplete.el | 361 + xemacs-packages/lisp/edit-utils/icomplete.elc | Bin 0 -> 7754 bytes xemacs-packages/lisp/edit-utils/id-select.el | 1291 ++ xemacs-packages/lisp/edit-utils/id-select.elc | Bin 0 -> 22855 bytes xemacs-packages/lisp/edit-utils/info-look.el | 787 + xemacs-packages/lisp/edit-utils/info-look.elc | Bin 0 -> 20830 bytes xemacs-packages/lisp/edit-utils/iswitchb.el | 1357 ++ xemacs-packages/lisp/edit-utils/iswitchb.elc | Bin 0 -> 23780 bytes xemacs-packages/lisp/edit-utils/lazy-lock.el | 1076 ++ xemacs-packages/lisp/edit-utils/lazy-lock.elc | Bin 0 -> 18642 bytes xemacs-packages/lisp/edit-utils/lazy-shot.el | 327 + xemacs-packages/lisp/edit-utils/lazy-shot.elc | Bin 0 -> 7927 bytes .../lisp/edit-utils/lispm-fonts.el | 191 + .../lisp/edit-utils/lispm-fonts.elc | Bin 0 -> 3410 bytes xemacs-packages/lisp/edit-utils/live-icon.el | 328 + xemacs-packages/lisp/edit-utils/live-icon.elc | Bin 0 -> 2390 bytes xemacs-packages/lisp/edit-utils/makesum.el | 125 + xemacs-packages/lisp/edit-utils/makesum.elc | Bin 0 -> 1858 bytes xemacs-packages/lisp/edit-utils/man.el | 761 + xemacs-packages/lisp/edit-utils/man.elc | Bin 0 -> 10618 bytes xemacs-packages/lisp/edit-utils/mic-paren.el | 1444 ++ xemacs-packages/lisp/edit-utils/mic-paren.elc | Bin 0 -> 26783 bytes .../lisp/edit-utils/mode-motion+.el | 2203 +++ .../lisp/edit-utils/mode-motion+.elc | Bin 0 -> 41773 bytes .../lisp/edit-utils/narrow-stack.el | 120 + .../lisp/edit-utils/narrow-stack.elc | Bin 0 -> 2348 bytes xemacs-packages/lisp/edit-utils/outl-mouse.el | 684 + .../lisp/edit-utils/outl-mouse.elc | Bin 0 -> 14650 bytes xemacs-packages/lisp/edit-utils/page-ext.el | 793 ++ xemacs-packages/lisp/edit-utils/page-ext.elc | Bin 0 -> 12294 bytes xemacs-packages/lisp/edit-utils/paren.el | 413 + xemacs-packages/lisp/edit-utils/paren.elc | Bin 0 -> 8124 bytes .../lisp/edit-utils/permanent-buffers.el | 228 + .../lisp/edit-utils/permanent-buffers.elc | Bin 0 -> 4217 bytes xemacs-packages/lisp/edit-utils/popper.el | 1817 +++ xemacs-packages/lisp/edit-utils/popper.elc | Bin 0 -> 34965 bytes .../lisp/edit-utils/power-macros.el | 1932 +++ .../lisp/edit-utils/power-macros.elc | Bin 0 -> 35372 bytes .../lisp/edit-utils/recent-files.el | 769 + .../lisp/edit-utils/recent-files.elc | Bin 0 -> 16620 bytes xemacs-packages/lisp/edit-utils/redo.el | 203 + xemacs-packages/lisp/edit-utils/redo.elc | Bin 0 -> 2415 bytes xemacs-packages/lisp/edit-utils/reportmail.el | 997 ++ .../lisp/edit-utils/reportmail.elc | Bin 0 -> 19123 bytes xemacs-packages/lisp/edit-utils/resume.el | 131 + xemacs-packages/lisp/edit-utils/resume.elc | Bin 0 -> 2168 bytes .../lisp/edit-utils/rsz-minibuf.el | 233 + .../lisp/edit-utils/rsz-minibuf.elc | Bin 0 -> 5126 bytes xemacs-packages/lisp/edit-utils/saveconf.el | 285 + xemacs-packages/lisp/edit-utils/saveconf.elc | Bin 0 -> 5219 bytes xemacs-packages/lisp/edit-utils/savehist.el | 375 + xemacs-packages/lisp/edit-utils/savehist.elc | Bin 0 -> 9377 bytes xemacs-packages/lisp/edit-utils/saveplace.el | 243 + xemacs-packages/lisp/edit-utils/saveplace.elc | Bin 0 -> 4963 bytes .../lisp/edit-utils/scroll-in-place.el | 1588 +++ .../lisp/edit-utils/scroll-in-place.elc | Bin 0 -> 32726 bytes .../lisp/edit-utils/search-buffers.el | 300 + .../lisp/edit-utils/search-buffers.elc | Bin 0 -> 4834 bytes xemacs-packages/lisp/edit-utils/setnu.el | 449 + xemacs-packages/lisp/edit-utils/setnu.elc | Bin 0 -> 9045 bytes xemacs-packages/lisp/edit-utils/shell-font.el | 161 + .../lisp/edit-utils/shell-font.elc | Bin 0 -> 3506 bytes xemacs-packages/lisp/edit-utils/tempo.el | 759 + xemacs-packages/lisp/edit-utils/tempo.elc | Bin 0 -> 17315 bytes .../lisp/edit-utils/toolbar-utils.el | 484 + .../lisp/edit-utils/toolbar-utils.elc | Bin 0 -> 14318 bytes xemacs-packages/lisp/edit-utils/tree-menu.el | 199 + xemacs-packages/lisp/edit-utils/tree-menu.elc | Bin 0 -> 3269 bytes xemacs-packages/lisp/edit-utils/uniquify.el | 478 + xemacs-packages/lisp/edit-utils/uniquify.elc | Bin 0 -> 10592 bytes .../lisp/edit-utils/vertical-mode.el | 76 + .../lisp/edit-utils/vertical-mode.elc | Bin 0 -> 1534 bytes .../lisp/edit-utils/where-was-i-db.el | 364 + .../lisp/edit-utils/where-was-i-db.elc | Bin 0 -> 7937 bytes xemacs-packages/lisp/edit-utils/winring.el | 594 + xemacs-packages/lisp/edit-utils/winring.elc | Bin 0 -> 11200 bytes xemacs-packages/lisp/mail-lib/ChangeLog | 1378 ++ xemacs-packages/lisp/mail-lib/_pkg.el | 5 + .../lisp/mail-lib/auto-autoloads.el | 572 + .../lisp/mail-lib/auto-autoloads.elc | Bin 0 -> 33022 bytes xemacs-packages/lisp/mail-lib/base64.el | 278 + xemacs-packages/lisp/mail-lib/base64.elc | Bin 0 -> 5639 bytes .../lisp/mail-lib/browse-url-xemacs.el | 170 + .../lisp/mail-lib/browse-url-xemacs.elc | Bin 0 -> 5138 bytes xemacs-packages/lisp/mail-lib/browse-url.el | 1604 +++ xemacs-packages/lisp/mail-lib/browse-url.elc | Bin 0 -> 45812 bytes xemacs-packages/lisp/mail-lib/custom-load.el | 25 + xemacs-packages/lisp/mail-lib/custom-load.elc | Bin 0 -> 1286 bytes .../lisp/mail-lib/highlight-headers.el | 556 + .../lisp/mail-lib/highlight-headers.elc | Bin 0 -> 10570 bytes xemacs-packages/lisp/mail-lib/mail-abbrevs.el | 649 + .../lisp/mail-lib/mail-abbrevs.elc | Bin 0 -> 10830 bytes xemacs-packages/lisp/mail-lib/mail-extr.el | 2132 +++ xemacs-packages/lisp/mail-lib/mail-extr.elc | Bin 0 -> 24527 bytes xemacs-packages/lisp/mail-lib/mail-utils.el | 315 + xemacs-packages/lisp/mail-lib/mail-utils.elc | Bin 0 -> 6010 bytes xemacs-packages/lisp/mail-lib/mailheader.el | 195 + xemacs-packages/lisp/mail-lib/mailheader.elc | Bin 0 -> 5698 bytes xemacs-packages/lisp/mail-lib/netrc.el | 203 + xemacs-packages/lisp/mail-lib/netrc.elc | Bin 0 -> 3809 bytes xemacs-packages/lisp/mail-lib/pop3.el | 789 + xemacs-packages/lisp/mail-lib/pop3.elc | Bin 0 -> 15181 bytes xemacs-packages/lisp/mail-lib/reporter.el | 413 + xemacs-packages/lisp/mail-lib/reporter.elc | Bin 0 -> 8825 bytes xemacs-packages/lisp/mail-lib/rfc2104.el | 120 + xemacs-packages/lisp/mail-lib/rfc2104.elc | Bin 0 -> 1583 bytes xemacs-packages/lisp/mail-lib/rfc822.el | 329 + xemacs-packages/lisp/mail-lib/rfc822.elc | Bin 0 -> 4464 bytes xemacs-packages/lisp/mail-lib/rmail-mini.el | 74 + xemacs-packages/lisp/mail-lib/rmail-mini.elc | Bin 0 -> 1471 bytes xemacs-packages/lisp/mail-lib/rmailout.el | 263 + xemacs-packages/lisp/mail-lib/rmailout.elc | Bin 0 -> 5725 bytes xemacs-packages/lisp/mail-lib/sendmail.el | 1849 +++ xemacs-packages/lisp/mail-lib/sendmail.elc | Bin 0 -> 40322 bytes xemacs-packages/lisp/mail-lib/smtpmail.el | 983 ++ xemacs-packages/lisp/mail-lib/smtpmail.elc | Bin 0 -> 17480 bytes xemacs-packages/lisp/mail-lib/starttls.el | 296 + xemacs-packages/lisp/mail-lib/starttls.elc | Bin 0 -> 5659 bytes xemacs-packages/lisp/mail-lib/tls.el | 159 + xemacs-packages/lisp/mail-lib/tls.elc | Bin 0 -> 3884 bytes xemacs-packages/lisp/net-utils/ChangeLog | 469 + xemacs-packages/lisp/net-utils/_pkg.el | 5 + .../lisp/net-utils/auto-autoloads.el | 186 + .../lisp/net-utils/auto-autoloads.elc | Bin 0 -> 7060 bytes .../lisp/net-utils/browse-cltl2.el | 482 + .../lisp/net-utils/browse-cltl2.elc | Bin 0 -> 11384 bytes xemacs-packages/lisp/net-utils/custom-load.el | 31 + .../lisp/net-utils/custom-load.elc | Bin 0 -> 1405 bytes xemacs-packages/lisp/net-utils/dig.el | 188 + xemacs-packages/lisp/net-utils/dig.elc | Bin 0 -> 4530 bytes xemacs-packages/lisp/net-utils/dns-mode.el | 198 + xemacs-packages/lisp/net-utils/dns-mode.elc | Bin 0 -> 5184 bytes xemacs-packages/lisp/net-utils/dns.el | 374 + xemacs-packages/lisp/net-utils/dns.elc | Bin 0 -> 7781 bytes xemacs-packages/lisp/net-utils/feedmail.el | 3160 ++++ xemacs-packages/lisp/net-utils/feedmail.elc | Bin 0 -> 92642 bytes .../lisp/net-utils/google-query.el | 351 + .../lisp/net-utils/google-query.elc | Bin 0 -> 7634 bytes xemacs-packages/lisp/net-utils/metamail.el | 226 + xemacs-packages/lisp/net-utils/metamail.elc | Bin 0 -> 4503 bytes xemacs-packages/lisp/net-utils/mozmail.el | 463 + xemacs-packages/lisp/net-utils/mozmail.elc | Bin 0 -> 9270 bytes xemacs-packages/lisp/net-utils/net-utils.el | 674 + xemacs-packages/lisp/net-utils/net-utils.elc | Bin 0 -> 13077 bytes xemacs-packages/lisp/net-utils/rcompile.el | 197 + xemacs-packages/lisp/net-utils/rcompile.elc | Bin 0 -> 3655 bytes xemacs-packages/lisp/net-utils/shadowfile.el | 863 ++ xemacs-packages/lisp/net-utils/shadowfile.elc | Bin 0 -> 21092 bytes xemacs-packages/lisp/net-utils/webjump.el | 454 + xemacs-packages/lisp/net-utils/webjump.elc | Bin 0 -> 11170 bytes xemacs-packages/lisp/net-utils/webster-www.el | 71 + .../lisp/net-utils/webster-www.elc | Bin 0 -> 1751 bytes xemacs-packages/lisp/net-utils/xemacsbug.el | 353 + xemacs-packages/lisp/net-utils/xemacsbug.elc | Bin 0 -> 8688 bytes xemacs-packages/lisp/net-utils/xml.el | 507 + xemacs-packages/lisp/net-utils/xml.elc | Bin 0 -> 8202 bytes xemacs-packages/lisp/os-utils/ChangeLog | 317 + xemacs-packages/lisp/os-utils/_pkg.el | 5 + xemacs-packages/lisp/os-utils/arc-mode.el | 1598 +++ xemacs-packages/lisp/os-utils/arc-mode.elc | Bin 0 -> 35792 bytes .../lisp/os-utils/auto-autoloads.el | 400 + .../lisp/os-utils/auto-autoloads.elc | Bin 0 -> 16567 bytes xemacs-packages/lisp/os-utils/background.el | 184 + xemacs-packages/lisp/os-utils/background.elc | Bin 0 -> 4175 bytes xemacs-packages/lisp/os-utils/crypt.el | 2666 ++++ xemacs-packages/lisp/os-utils/crypt.elc | Bin 0 -> 34003 bytes xemacs-packages/lisp/os-utils/custom-load.el | 26 + xemacs-packages/lisp/os-utils/custom-load.elc | Bin 0 -> 1198 bytes xemacs-packages/lisp/os-utils/ftelnet.el | 425 + xemacs-packages/lisp/os-utils/ftelnet.elc | Bin 0 -> 9635 bytes xemacs-packages/lisp/os-utils/inf-lisp.el | 636 + xemacs-packages/lisp/os-utils/inf-lisp.elc | Bin 0 -> 15697 bytes xemacs-packages/lisp/os-utils/jka-compr.el | 989 ++ xemacs-packages/lisp/os-utils/jka-compr.elc | Bin 0 -> 17266 bytes xemacs-packages/lisp/os-utils/kermit.el | 151 + xemacs-packages/lisp/os-utils/kermit.elc | Bin 0 -> 2800 bytes xemacs-packages/lisp/os-utils/ledit.el | 157 + xemacs-packages/lisp/os-utils/ledit.elc | Bin 0 -> 4270 bytes xemacs-packages/lisp/os-utils/mchat.el | 1353 ++ xemacs-packages/lisp/os-utils/mchat.elc | Bin 0 -> 29255 bytes xemacs-packages/lisp/os-utils/rlogin.el | 368 + xemacs-packages/lisp/os-utils/rlogin.elc | Bin 0 -> 9014 bytes xemacs-packages/lisp/os-utils/spell.el | 156 + xemacs-packages/lisp/os-utils/spell.elc | Bin 0 -> 3036 bytes xemacs-packages/lisp/os-utils/ssh.el | 363 + xemacs-packages/lisp/os-utils/ssh.elc | Bin 0 -> 8625 bytes xemacs-packages/lisp/os-utils/tar-mode.el | 1407 ++ xemacs-packages/lisp/os-utils/tar-mode.elc | Bin 0 -> 28845 bytes xemacs-packages/lisp/os-utils/telnet.el | 341 + xemacs-packages/lisp/os-utils/telnet.elc | Bin 0 -> 7359 bytes xemacs-packages/lisp/os-utils/terminal.el | 1280 ++ xemacs-packages/lisp/os-utils/terminal.elc | Bin 0 -> 24043 bytes xemacs-packages/lisp/os-utils/uncompress.el | 111 + xemacs-packages/lisp/os-utils/uncompress.elc | Bin 0 -> 2047 bytes xemacs-packages/lisp/perl-modes/ChangeLog | 103 + xemacs-packages/lisp/perl-modes/_pkg.el | 5 + .../lisp/perl-modes/auto-autoloads.el | 193 + .../lisp/perl-modes/auto-autoloads.elc | Bin 0 -> 8865 bytes xemacs-packages/lisp/perl-modes/cperl-mode.el | 8578 +++++++++++ .../lisp/perl-modes/cperl-mode.elc | Bin 0 -> 154535 bytes .../lisp/perl-modes/custom-load.el | 16 + .../lisp/perl-modes/custom-load.elc | Bin 0 -> 969 bytes xemacs-packages/lisp/perl-modes/perl-mode.el | 712 + xemacs-packages/lisp/perl-modes/perl-mode.elc | Bin 0 -> 12694 bytes xemacs-packages/lisp/pgg/ChangeLog | 507 + xemacs-packages/lisp/pgg/README | 4 + xemacs-packages/lisp/pgg/_pkg.el | 5 + xemacs-packages/lisp/pgg/auto-autoloads.el | 74 + xemacs-packages/lisp/pgg/auto-autoloads.elc | Bin 0 -> 3234 bytes xemacs-packages/lisp/pgg/custom-load.el | 14 + xemacs-packages/lisp/pgg/custom-load.elc | Bin 0 -> 861 bytes xemacs-packages/lisp/pgg/pgg-def.el | 89 + xemacs-packages/lisp/pgg/pgg-def.elc | Bin 0 -> 2316 bytes xemacs-packages/lisp/pgg/pgg-gpg.el | 275 + xemacs-packages/lisp/pgg/pgg-gpg.elc | Bin 0 -> 8104 bytes xemacs-packages/lisp/pgg/pgg-parse.el | 515 + xemacs-packages/lisp/pgg/pgg-parse.elc | Bin 0 -> 10902 bytes xemacs-packages/lisp/pgg/pgg-pgp.el | 245 + xemacs-packages/lisp/pgg/pgg-pgp.elc | Bin 0 -> 6288 bytes xemacs-packages/lisp/pgg/pgg-pgp5.el | 250 + xemacs-packages/lisp/pgg/pgg-pgp5.elc | Bin 0 -> 6595 bytes xemacs-packages/lisp/pgg/pgg.el | 371 + xemacs-packages/lisp/pgg/pgg.elc | Bin 0 -> 11433 bytes xemacs-packages/lisp/prog-modes/ChangeLog | 1560 ++ xemacs-packages/lisp/prog-modes/_pkg.el | 5 + xemacs-packages/lisp/prog-modes/asm-mode.el | 265 + xemacs-packages/lisp/prog-modes/asm-mode.elc | Bin 0 -> 5204 bytes .../lisp/prog-modes/auto-autoloads.el | 1407 ++ .../lisp/prog-modes/auto-autoloads.elc | Bin 0 -> 57798 bytes .../lisp/prog-modes/autoconf-mode.el | 87 + .../lisp/prog-modes/autoconf-mode.elc | Bin 0 -> 2444 bytes xemacs-packages/lisp/prog-modes/awk-mode.el | 181 + xemacs-packages/lisp/prog-modes/awk-mode.elc | Bin 0 -> 3476 bytes xemacs-packages/lisp/prog-modes/cl-indent.el | 513 + xemacs-packages/lisp/prog-modes/cl-indent.elc | Bin 0 -> 6540 bytes .../lisp/prog-modes/custom-load.el | 65 + .../lisp/prog-modes/custom-load.elc | Bin 0 -> 2787 bytes xemacs-packages/lisp/prog-modes/cvs.el | 2028 +++ xemacs-packages/lisp/prog-modes/cvs.elc | Bin 0 -> 45863 bytes xemacs-packages/lisp/prog-modes/diff-mode.el | 1393 ++ xemacs-packages/lisp/prog-modes/diff-mode.elc | Bin 0 -> 31470 bytes xemacs-packages/lisp/prog-modes/eiffel.el | 2070 +++ xemacs-packages/lisp/prog-modes/eiffel.elc | Bin 0 -> 48178 bytes xemacs-packages/lisp/prog-modes/icon.el | 706 + xemacs-packages/lisp/prog-modes/icon.elc | Bin 0 -> 13530 bytes .../lisp/prog-modes/javascript-mode.el | 389 + .../lisp/prog-modes/javascript-mode.elc | Bin 0 -> 7377 bytes xemacs-packages/lisp/prog-modes/ksh-mode.el | 1341 ++ xemacs-packages/lisp/prog-modes/ksh-mode.elc | Bin 0 -> 20348 bytes xemacs-packages/lisp/prog-modes/lua-mode.el | 1115 ++ xemacs-packages/lisp/prog-modes/lua-mode.elc | Bin 0 -> 21014 bytes xemacs-packages/lisp/prog-modes/m4-mode.el | 215 + xemacs-packages/lisp/prog-modes/m4-mode.elc | Bin 0 -> 3781 bytes xemacs-packages/lisp/prog-modes/make-mode.el | 1684 +++ xemacs-packages/lisp/prog-modes/make-mode.elc | Bin 0 -> 33726 bytes .../lisp/prog-modes/mode-compile.el | 2667 ++++ .../lisp/prog-modes/mode-compile.elc | Bin 0 -> 65989 bytes xemacs-packages/lisp/prog-modes/modula2.el | 583 + xemacs-packages/lisp/prog-modes/modula2.elc | Bin 0 -> 12263 bytes xemacs-packages/lisp/prog-modes/old-c-mode.el | 2024 +++ .../lisp/prog-modes/old-c-mode.elc | Bin 0 -> 31613 bytes xemacs-packages/lisp/prog-modes/p4.el | 3694 +++++ xemacs-packages/lisp/prog-modes/p4.elc | Bin 0 -> 82972 bytes xemacs-packages/lisp/prog-modes/pascal.el | 1597 +++ xemacs-packages/lisp/prog-modes/pascal.elc | Bin 0 -> 31889 bytes xemacs-packages/lisp/prog-modes/php-mode.el | 852 ++ xemacs-packages/lisp/prog-modes/php-mode.elc | Bin 0 -> 12030 bytes xemacs-packages/lisp/prog-modes/postscript.el | 357 + .../lisp/prog-modes/postscript.elc | Bin 0 -> 7515 bytes xemacs-packages/lisp/prog-modes/prolog.el | 336 + xemacs-packages/lisp/prog-modes/prolog.elc | Bin 0 -> 7997 bytes xemacs-packages/lisp/prog-modes/rexx-mode.el | 620 + xemacs-packages/lisp/prog-modes/rexx-mode.elc | Bin 0 -> 16404 bytes .../lisp/prog-modes/rpm-spec-mode.el | 1353 ++ .../lisp/prog-modes/rpm-spec-mode.elc | Bin 0 -> 34971 bytes xemacs-packages/lisp/prog-modes/simula.el | 1330 ++ xemacs-packages/lisp/prog-modes/simula.elc | Bin 0 -> 29227 bytes xemacs-packages/lisp/prog-modes/sql.el | 2979 ++++ xemacs-packages/lisp/prog-modes/sql.elc | Bin 0 -> 99889 bytes xemacs-packages/lisp/prog-modes/tcl.el | 2020 +++ xemacs-packages/lisp/prog-modes/tcl.elc | Bin 0 -> 39112 bytes xemacs-packages/lisp/prog-modes/teco.el | 1947 +++ xemacs-packages/lisp/prog-modes/teco.elc | Bin 0 -> 28998 bytes xemacs-packages/lisp/prog-modes/uil-mode.el | 109 + xemacs-packages/lisp/prog-modes/uil-mode.elc | Bin 0 -> 3088 bytes .../lisp/prog-modes/verilog-mode.el | 8268 +++++++++++ .../lisp/prog-modes/verilog-mode.elc | Bin 0 -> 224316 bytes xemacs-packages/lisp/prog-modes/vrml-mode.el | 787 + xemacs-packages/lisp/prog-modes/vrml-mode.elc | Bin 0 -> 12553 bytes xemacs-packages/lisp/python-modes/ChangeLog | 75 + xemacs-packages/lisp/python-modes/_pkg.el | 5 + .../lisp/python-modes/auto-autoloads.el | 117 + .../lisp/python-modes/auto-autoloads.elc | Bin 0 -> 5734 bytes .../lisp/python-modes/custom-load.el | 10 + .../lisp/python-modes/custom-load.elc | Bin 0 -> 729 bytes .../lisp/python-modes/pydoc-el-README | 44 + xemacs-packages/lisp/python-modes/pydoc.el | 644 + xemacs-packages/lisp/python-modes/pydoc.elc | Bin 0 -> 14482 bytes .../lisp/python-modes/python-mode.el | 3817 +++++ .../lisp/python-modes/python-mode.elc | Bin 0 -> 98508 bytes xemacs-packages/lisp/re-builder/ChangeLog | 100 + xemacs-packages/lisp/re-builder/_pkg.el | 5 + .../lisp/re-builder/auto-autoloads.el | 20 + .../lisp/re-builder/auto-autoloads.elc | Bin 0 -> 1032 bytes .../lisp/re-builder/custom-load.el | 10 + .../lisp/re-builder/custom-load.elc | Bin 0 -> 728 bytes xemacs-packages/lisp/re-builder/re-builder.el | 952 ++ .../lisp/re-builder/re-builder.elc | Bin 0 -> 21219 bytes xemacs-packages/lisp/sh-script/ChangeLog | 127 + xemacs-packages/lisp/sh-script/_pkg.el | 5 + .../lisp/sh-script/auto-autoloads.el | 62 + .../lisp/sh-script/auto-autoloads.elc | Bin 0 -> 5427 bytes xemacs-packages/lisp/sh-script/custom-load.el | 15 + .../lisp/sh-script/custom-load.elc | Bin 0 -> 875 bytes xemacs-packages/lisp/sh-script/executable.el | 315 + xemacs-packages/lisp/sh-script/executable.elc | Bin 0 -> 7590 bytes xemacs-packages/lisp/sh-script/sh-script.el | 3589 +++++ xemacs-packages/lisp/sh-script/sh-script.elc | Bin 0 -> 78392 bytes xemacs-packages/lisp/speedbar/ChangeLog | 1626 +++ xemacs-packages/lisp/speedbar/_pkg.el | 5 + .../lisp/speedbar/auto-autoloads.el | 74 + .../lisp/speedbar/auto-autoloads.elc | Bin 0 -> 2666 bytes xemacs-packages/lisp/speedbar/bigclock.el | 164 + xemacs-packages/lisp/speedbar/bigclock.elc | Bin 0 -> 3935 bytes xemacs-packages/lisp/speedbar/custom-load.el | 15 + xemacs-packages/lisp/speedbar/custom-load.elc | Bin 0 -> 873 bytes xemacs-packages/lisp/speedbar/dframe.el | 1026 ++ xemacs-packages/lisp/speedbar/dframe.elc | Bin 0 -> 21069 bytes xemacs-packages/lisp/speedbar/rpm.el | 198 + xemacs-packages/lisp/speedbar/rpm.elc | Bin 0 -> 4449 bytes xemacs-packages/lisp/speedbar/sb-ant.el | 108 + xemacs-packages/lisp/speedbar/sb-ant.elc | Bin 0 -> 1613 bytes .../lisp/speedbar/sb-box-minus.xpm | 22 + xemacs-packages/lisp/speedbar/sb-box-plus.xpm | 22 + xemacs-packages/lisp/speedbar/sb-box.xpm | 22 + xemacs-packages/lisp/speedbar/sb-chk.xpm | 20 + .../lisp/speedbar/sb-dir-minus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-dir-plus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-dir.xpm | 23 + .../lisp/speedbar/sb-doc-minus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-doc-plus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-doc.xpm | 23 + xemacs-packages/lisp/speedbar/sb-gud.el | 243 + xemacs-packages/lisp/speedbar/sb-gud.elc | Bin 0 -> 4433 bytes xemacs-packages/lisp/speedbar/sb-html.el | 118 + xemacs-packages/lisp/speedbar/sb-html.elc | Bin 0 -> 1609 bytes xemacs-packages/lisp/speedbar/sb-image.el | 284 + xemacs-packages/lisp/speedbar/sb-image.elc | Bin 0 -> 10839 bytes xemacs-packages/lisp/speedbar/sb-info.el | 251 + xemacs-packages/lisp/speedbar/sb-info.elc | Bin 0 -> 5410 bytes xemacs-packages/lisp/speedbar/sb-info.xpm | 22 + xemacs-packages/lisp/speedbar/sb-label.xpm | 22 + xemacs-packages/lisp/speedbar/sb-mail.xpm | 22 + xemacs-packages/lisp/speedbar/sb-obj.xpm | 20 + xemacs-packages/lisp/speedbar/sb-objod.xpm | 21 + xemacs-packages/lisp/speedbar/sb-pg-minus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-pg-plus.xpm | 23 + xemacs-packages/lisp/speedbar/sb-pg.xpm | 23 + xemacs-packages/lisp/speedbar/sb-rmail.el | 158 + xemacs-packages/lisp/speedbar/sb-rmail.elc | Bin 0 -> 4117 bytes xemacs-packages/lisp/speedbar/sb-ro.xpm | 17 + xemacs-packages/lisp/speedbar/sb-tag-gt.xpm | 22 + .../lisp/speedbar/sb-tag-minus.xpm | 22 + xemacs-packages/lisp/speedbar/sb-tag-plus.xpm | 22 + xemacs-packages/lisp/speedbar/sb-tag-type.xpm | 22 + xemacs-packages/lisp/speedbar/sb-tag-v.xpm | 22 + xemacs-packages/lisp/speedbar/sb-tag.xpm | 22 + xemacs-packages/lisp/speedbar/sb-texinfo.el | 219 + xemacs-packages/lisp/speedbar/sb-texinfo.elc | Bin 0 -> 3688 bytes xemacs-packages/lisp/speedbar/sb-w3.el | 151 + xemacs-packages/lisp/speedbar/sb-w3.elc | Bin 0 -> 2819 bytes xemacs-packages/lisp/speedbar/speedbar.el | 3952 +++++ xemacs-packages/lisp/speedbar/speedbar.elc | Bin 0 -> 99736 bytes xemacs-packages/lisp/template/ChangeLog | 619 + xemacs-packages/lisp/template/template.el | 2609 ++++ xemacs-packages/lisp/template/template.elc | Bin 0 -> 82069 bytes xemacs-packages/lisp/texinfo/ChangeLog | 450 + xemacs-packages/lisp/texinfo/_pkg.el | 5 + .../lisp/texinfo/auto-autoloads.el | 186 + .../lisp/texinfo/auto-autoloads.elc | Bin 0 -> 10826 bytes xemacs-packages/lisp/texinfo/custom-load.el | 13 + xemacs-packages/lisp/texinfo/custom-load.elc | Bin 0 -> 826 bytes xemacs-packages/lisp/texinfo/detexinfo.el | 275 + xemacs-packages/lisp/texinfo/detexinfo.elc | Bin 0 -> 6803 bytes xemacs-packages/lisp/texinfo/informat.el | 546 + xemacs-packages/lisp/texinfo/informat.elc | Bin 0 -> 8037 bytes xemacs-packages/lisp/texinfo/makeinfo.el | 258 + xemacs-packages/lisp/texinfo/makeinfo.elc | Bin 0 -> 4315 bytes xemacs-packages/lisp/texinfo/tex-mode.el | 892 ++ xemacs-packages/lisp/texinfo/tex-mode.elc | Bin 0 -> 26144 bytes xemacs-packages/lisp/texinfo/texinfmt.el | 4426 ++++++ xemacs-packages/lisp/texinfo/texinfmt.elc | Bin 0 -> 71457 bytes xemacs-packages/lisp/texinfo/texinfo.el | 1062 ++ xemacs-packages/lisp/texinfo/texinfo.elc | Bin 0 -> 32205 bytes xemacs-packages/lisp/texinfo/texnfo-tex.el | 370 + xemacs-packages/lisp/texinfo/texnfo-tex.elc | Bin 0 -> 8321 bytes xemacs-packages/lisp/texinfo/texnfo-upd.el | 2043 +++ xemacs-packages/lisp/texinfo/texnfo-upd.elc | Bin 0 -> 41379 bytes xemacs-packages/lisp/text-modes/ChangeLog | 947 ++ xemacs-packages/lisp/text-modes/_pkg.el | 5 + xemacs-packages/lisp/text-modes/ansi-color.el | 645 + .../lisp/text-modes/ansi-color.elc | Bin 0 -> 15978 bytes .../lisp/text-modes/apache-mode.el | 561 + .../lisp/text-modes/apache-mode.elc | Bin 0 -> 14780 bytes .../lisp/text-modes/auto-autoloads.el | 904 ++ .../lisp/text-modes/auto-autoloads.elc | Bin 0 -> 37525 bytes xemacs-packages/lisp/text-modes/autoinsert.el | 281 + .../lisp/text-modes/autoinsert.elc | Bin 0 -> 6976 bytes xemacs-packages/lisp/text-modes/crontab.el | 162 + xemacs-packages/lisp/text-modes/crontab.elc | Bin 0 -> 3261 bytes xemacs-packages/lisp/text-modes/css-mode.el | 626 + xemacs-packages/lisp/text-modes/css-mode.elc | Bin 0 -> 13605 bytes .../lisp/text-modes/custom-load.el | 47 + .../lisp/text-modes/custom-load.elc | Bin 0 -> 2059 bytes .../lisp/text-modes/desktop-entry-mode.el | 197 + .../lisp/text-modes/desktop-entry-mode.elc | Bin 0 -> 4620 bytes xemacs-packages/lisp/text-modes/filladapt.el | 988 ++ xemacs-packages/lisp/text-modes/filladapt.elc | Bin 0 -> 21150 bytes xemacs-packages/lisp/text-modes/flyspell.el | 2198 +++ xemacs-packages/lisp/text-modes/flyspell.elc | Bin 0 -> 41005 bytes xemacs-packages/lisp/text-modes/folding.el | 5356 +++++++ xemacs-packages/lisp/text-modes/folding.elc | Bin 0 -> 79907 bytes xemacs-packages/lisp/text-modes/hexl.el | 962 ++ xemacs-packages/lisp/text-modes/hexl.elc | Bin 0 -> 22795 bytes xemacs-packages/lisp/text-modes/htmlize.el | 1578 ++ xemacs-packages/lisp/text-modes/htmlize.elc | Bin 0 -> 44340 bytes xemacs-packages/lisp/text-modes/image-mode.el | 201 + .../lisp/text-modes/image-mode.elc | Bin 0 -> 4616 bytes xemacs-packages/lisp/text-modes/iso-acc.el | 504 + xemacs-packages/lisp/text-modes/iso-acc.elc | Bin 0 -> 12206 bytes xemacs-packages/lisp/text-modes/iso-ascii.el | 148 + xemacs-packages/lisp/text-modes/iso-ascii.elc | Bin 0 -> 2727 bytes xemacs-packages/lisp/text-modes/iso-cvt.el | 719 + xemacs-packages/lisp/text-modes/iso-cvt.elc | Bin 0 -> 13138 bytes xemacs-packages/lisp/text-modes/iso-insert.el | 634 + .../lisp/text-modes/iso-insert.elc | Bin 0 -> 9787 bytes xemacs-packages/lisp/text-modes/iso-swed.el | 153 + xemacs-packages/lisp/text-modes/iso-swed.elc | Bin 0 -> 2557 bytes xemacs-packages/lisp/text-modes/nroff-mode.el | 289 + .../lisp/text-modes/nroff-mode.elc | Bin 0 -> 5709 bytes xemacs-packages/lisp/text-modes/po-compat.el | 263 + xemacs-packages/lisp/text-modes/po-compat.elc | Bin 0 -> 4857 bytes xemacs-packages/lisp/text-modes/po-mode.el | 3321 +++++ xemacs-packages/lisp/text-modes/po-mode.elc | Bin 0 -> 74806 bytes .../lisp/text-modes/rtf-support.el | 744 + .../lisp/text-modes/rtf-support.elc | Bin 0 -> 16331 bytes xemacs-packages/lisp/text-modes/scribe.el | 323 + xemacs-packages/lisp/text-modes/scribe.elc | Bin 0 -> 7302 bytes xemacs-packages/lisp/text-modes/swedish.el | 156 + xemacs-packages/lisp/text-modes/swedish.elc | Bin 0 -> 2396 bytes xemacs-packages/lisp/text-modes/tabify.el | 92 + xemacs-packages/lisp/text-modes/tabify.elc | Bin 0 -> 1750 bytes xemacs-packages/lisp/text-modes/tpum.el | 1590 +++ xemacs-packages/lisp/text-modes/tpum.elc | Bin 0 -> 117329 bytes xemacs-packages/lisp/text-modes/underline.el | 118 + xemacs-packages/lisp/text-modes/underline.elc | Bin 0 -> 2367 bytes .../lisp/text-modes/whitespace-mode.el | 606 + .../lisp/text-modes/whitespace-mode.elc | Bin 0 -> 14151 bytes .../lisp/text-modes/whitespace-visual-mode.el | 645 + .../text-modes/whitespace-visual-mode.elc | Bin 0 -> 14735 bytes xemacs-packages/lisp/text-modes/whitespace.el | 856 ++ .../lisp/text-modes/whitespace.elc | Bin 0 -> 21433 bytes .../lisp/text-modes/winmgr-mode.el | 173 + .../lisp/text-modes/winmgr-mode.elc | Bin 0 -> 2645 bytes xemacs-packages/lisp/text-modes/ws-mode.el | 756 + xemacs-packages/lisp/text-modes/ws-mode.elc | Bin 0 -> 17742 bytes xemacs-packages/lisp/text-modes/xpm-mode.el | 464 + xemacs-packages/lisp/text-modes/xpm-mode.elc | Bin 0 -> 8270 bytes xemacs-packages/lisp/text-modes/xrdb-mode.el | 583 + xemacs-packages/lisp/text-modes/xrdb-mode.elc | Bin 0 -> 13028 bytes xemacs-packages/lisp/tramp/ChangeLog | 283 + xemacs-packages/lisp/tramp/ChangeLog.upstream | 798 ++ xemacs-packages/lisp/tramp/_pkg.el | 5 + xemacs-packages/lisp/tramp/auto-autoloads.el | 58 + xemacs-packages/lisp/tramp/auto-autoloads.elc | Bin 0 -> 4323 bytes xemacs-packages/lisp/tramp/custom-load.el | 10 + xemacs-packages/lisp/tramp/custom-load.elc | Bin 0 -> 736 bytes xemacs-packages/lisp/tramp/tramp-efs.el | 237 + xemacs-packages/lisp/tramp/tramp-efs.elc | Bin 0 -> 6020 bytes xemacs-packages/lisp/tramp/tramp-ftp.el | 141 + xemacs-packages/lisp/tramp/tramp-ftp.elc | Bin 0 -> 3067 bytes xemacs-packages/lisp/tramp/tramp-smb.el | 1056 ++ xemacs-packages/lisp/tramp/tramp-smb.elc | Bin 0 -> 31254 bytes xemacs-packages/lisp/tramp/tramp-util.el | 139 + xemacs-packages/lisp/tramp/tramp-util.elc | Bin 0 -> 4157 bytes xemacs-packages/lisp/tramp/tramp-uu.el | 92 + xemacs-packages/lisp/tramp/tramp-uu.elc | Bin 0 -> 1687 bytes xemacs-packages/lisp/tramp/tramp-vc.el | 538 + xemacs-packages/lisp/tramp/tramp-vc.elc | Bin 0 -> 11351 bytes xemacs-packages/lisp/tramp/tramp.el | 7772 ++++++++++ xemacs-packages/lisp/tramp/tramp.elc | Bin 0 -> 222089 bytes xemacs-packages/lisp/tramp/trampcache.el | 98 + xemacs-packages/lisp/tramp/trampcache.elc | Bin 0 -> 2338 bytes xemacs-packages/lisp/tramp/trampver.el | 42 + xemacs-packages/lisp/tramp/trampver.elc | Bin 0 -> 807 bytes .../lisp/twittering-mode-3.0.0/ChangeLog | 6829 +++++++++ .../lisp/twittering-mode-3.0.0/INSTALL | 46 + .../lisp/twittering-mode-3.0.0/INSTALL.ja | 49 + .../lisp/twittering-mode-3.0.0/LAST-VERSION | 1 + .../lisp/twittering-mode-3.0.0/Makefile | 65 + .../lisp/twittering-mode-3.0.0/NEWS | 655 + .../lisp/twittering-mode-3.0.0/NEWS.ja | 618 + .../lisp/twittering-mode-3.0.0/README.ja | 52 + .../twittering-mode-3.0.0/README.markdown | 338 + .../lisp/twittering-mode-3.0.0/TODO | 5 + .../lisp/twittering-mode-3.0.0/VERSION | 1 + .../lisp/twittering-mode-3.0.0/cert/.nosearch | 0 .../Equifax_Secure_Certificate_Authority.cer | 19 + .../cert/GeoTrust_Global_CA.cer | 20 + .../twittering-mode-3.0.0/cert/PCA-3G2.pem | 19 + .../lisp/twittering-mode-3.0.0/doc/.nosearch | 0 .../lisp/twittering-mode-3.0.0/doc/Makefile | 11 + .../twittering-mode-3.0.0/doc/manual/Makefile | 12 + .../twittering-mode-3.0.0/doc/manual/fdl.texi | 402 + .../doc/manual/twmode.texinfo | 222 + .../twittering-mode-3.0.0/doc/web/.htaccess | 5 + .../twittering-mode-3.0.0/doc/web/Makefile | 71 + .../doc/web/footer.rhtml | 27 + .../doc/web/header.rhtml | 50 + .../doc/web/how-to-contribute.text | 51 + .../doc/web/images/bottom.jpg | Bin 0 -> 2658 bytes .../doc/web/images/content.jpg | Bin 0 -> 449 bytes .../doc/web/images/famfamfam-logo.png | Bin 0 -> 2701 bytes .../doc/web/images/lang-en.png | Bin 0 -> 609 bytes .../doc/web/images/lang-ja.png | Bin 0 -> 420 bytes .../doc/web/images/logo.png | Bin 0 -> 18815 bytes .../doc/web/images/logo.svg | 295 + .../doc/web/images/menu.png | Bin 0 -> 525 bytes .../doc/web/images/pic.jpg | Bin 0 -> 21894 bytes .../doc/web/images/screen-friends-no-icon.png | Bin 0 -> 180074 bytes .../doc/web/images/screen-friends.png | Bin 0 -> 151293 bytes .../doc/web/images/screen-user-no-icon.png | Bin 0 -> 129220 bytes .../doc/web/images/screen-user.png | Bin 0 -> 107213 bytes .../doc/web/images/top.jpg | Bin 0 -> 935 bytes .../twittering-mode-3.0.0/doc/web/index.text | 45 + .../lisp/twittering-mode-3.0.0/doc/web/ja.po | 443 + .../twittering-mode-3.0.0/doc/web/publish.rb | 168 + .../doc/web/screenshot.text | 31 + .../twittering-mode-3.0.0/doc/web/style.css | 190 + .../twittering-mode-3.0.0/emacs21/.nosearch | 0 .../twittering-mode-3.0.0/emacs21/hex-util.el | 75 + .../twittering-mode-3.0.0/emacs21/sha1.el | 442 + .../lisp/twittering-mode-3.0.0/emacs21/tls.el | 209 + .../twittering-mode-3.0.0/howto/.nosearch | 0 .../lisp/twittering-mode-3.0.0/howto/release | 16 + .../lisp/twittering-mode-3.0.0/http-client.rb | 173 + .../lisp/twittering-mode-3.0.0/misc/.nosearch | 0 .../misc/twitter-icon.svg | 249 + .../misc/vernum-updater.rb | 208 + .../lisp/twittering-mode-3.0.0/test.el | 455 + .../lisp/twittering-mode-3.0.0/test/.nosearch | 0 .../test/el-test-runner.el | 72 + .../test/fixture/timeline-data.el | 309 + .../twittering-mode-3.0.0/test/run-test.sh | 29 + .../lisp/twittering-mode-3.0.0/test/server.rb | 90 + .../test/test-twittering-mode.el | 893 ++ .../twittering-mode-3.0.0/twittering-mode.el | 11860 ++++++++++++++++ .../url-emacs21/.nosearch | 0 .../url-emacs21/auto-autoloads.el | 664 + .../url-emacs21/custom-load.el | 47 + .../url-emacs21/docomp.el | 88 + .../url-emacs21/url-about.el | 100 + .../url-emacs21/url-auth.el | 324 + .../url-emacs21/url-auto.el | 664 + .../url-emacs21/url-buffer.el | 42 + .../url-emacs21/url-cache.el | 203 + .../url-emacs21/url-cid.el | 65 + .../url-emacs21/url-cookie.el | 468 + .../url-emacs21/url-dav.el | 973 ++ .../url-emacs21/url-dired.el | 102 + .../url-emacs21/url-expand.el | 143 + .../url-emacs21/url-file.el | 239 + .../url-emacs21/url-ftp.el | 44 + .../url-emacs21/url-gw.el | 264 + .../url-emacs21/url-handlers.el | 252 + .../url-emacs21/url-history.el | 199 + .../url-emacs21/url-http.el | 1234 ++ .../url-emacs21/url-https.el | 53 + .../url-emacs21/url-imap.el | 81 + .../url-emacs21/url-irc.el | 78 + .../url-emacs21/url-ldap.el | 233 + .../url-emacs21/url-mailto.el | 129 + .../url-emacs21/url-methods.el | 149 + .../url-emacs21/url-misc.el | 119 + .../url-emacs21/url-news.el | 135 + .../url-emacs21/url-nfs.el | 97 + .../url-emacs21/url-ns.el | 106 + .../url-emacs21/url-parse.el | 207 + .../url-emacs21/url-privacy.el | 83 + .../url-emacs21/url-proxy.el | 78 + .../url-emacs21/url-util.el | 485 + .../url-emacs21/url-vars.el | 438 + .../twittering-mode-3.0.0/url-emacs21/url.el | 273 + .../url-emacs21/vc-dav.el | 177 + .../twittering-mode-3.0.0/win-curl/.nosearch | 0 .../win-curl/README_j.txt | 58 + .../win-curl/curl-ca-bundle.crt | 4393 ++++++ .../twittering-mode-3.0.0/win-curl/curl.exe | Bin 0 -> 655360 bytes .../win-curl/docs/CHANGES | 1344 ++ .../win-curl/docs/COPYING | 21 + .../twittering-mode-3.0.0/win-curl/docs/FAQ | 782 + .../win-curl/docs/FEATURES | 108 + .../win-curl/docs/LICENSE.OpenSSL.txt | 127 + .../win-curl/docs/README | 70 + .../win-curl/docs/README.win32 | 22 + .../win-curl/docs/curl.html | 1436 ++ xemacs-packages/lisp/xemacs-base/ChangeLog | 1277 ++ xemacs-packages/lisp/xemacs-base/_pkg.el | 10 + xemacs-packages/lisp/xemacs-base/add-log.el | 1381 ++ xemacs-packages/lisp/xemacs-base/add-log.elc | Bin 0 -> 29668 bytes xemacs-packages/lisp/xemacs-base/advice.el | 3971 ++++++ xemacs-packages/lisp/xemacs-base/advice.elc | Bin 0 -> 45663 bytes .../lisp/xemacs-base/annotations.el | 451 + .../lisp/xemacs-base/annotations.elc | Bin 0 -> 12047 bytes xemacs-packages/lisp/xemacs-base/assoc.el | 143 + xemacs-packages/lisp/xemacs-base/assoc.elc | Bin 0 -> 4208 bytes .../lisp/xemacs-base/auto-autoloads.el | 1827 +++ .../lisp/xemacs-base/auto-autoloads.elc | Bin 0 -> 81747 bytes .../lisp/xemacs-base/case-table.el | 142 + .../lisp/xemacs-base/case-table.elc | Bin 0 -> 2835 bytes xemacs-packages/lisp/xemacs-base/chistory.el | 179 + xemacs-packages/lisp/xemacs-base/chistory.elc | Bin 0 -> 5130 bytes .../lisp/xemacs-base/comint-xemacs.el | 53 + .../lisp/xemacs-base/comint-xemacs.elc | Bin 0 -> 985 bytes xemacs-packages/lisp/xemacs-base/comint.el | 2943 ++++ xemacs-packages/lisp/xemacs-base/comint.elc | Bin 0 -> 68318 bytes xemacs-packages/lisp/xemacs-base/compile.el | 2368 +++ xemacs-packages/lisp/xemacs-base/compile.elc | Bin 0 -> 48419 bytes .../lisp/xemacs-base/custom-load.el | 40 + .../lisp/xemacs-base/custom-load.elc | Bin 0 -> 1581 bytes xemacs-packages/lisp/xemacs-base/debug.el | 827 ++ xemacs-packages/lisp/xemacs-base/debug.elc | Bin 0 -> 18007 bytes .../lisp/xemacs-base/easy-mmode.el | 605 + .../lisp/xemacs-base/easy-mmode.elc | Bin 0 -> 12360 bytes .../lisp/xemacs-base/ebuff-menu.el | 304 + .../lisp/xemacs-base/ebuff-menu.elc | Bin 0 -> 7785 bytes xemacs-packages/lisp/xemacs-base/echistory.el | 158 + .../lisp/xemacs-base/echistory.elc | Bin 0 -> 4284 bytes xemacs-packages/lisp/xemacs-base/edmacro.el | 745 + xemacs-packages/lisp/xemacs-base/edmacro.elc | Bin 0 -> 14216 bytes xemacs-packages/lisp/xemacs-base/ehelp.el | 418 + xemacs-packages/lisp/xemacs-base/ehelp.elc | Bin 0 -> 8990 bytes xemacs-packages/lisp/xemacs-base/electric.el | 210 + xemacs-packages/lisp/xemacs-base/electric.elc | Bin 0 -> 3009 bytes xemacs-packages/lisp/xemacs-base/enriched.el | 531 + xemacs-packages/lisp/xemacs-base/enriched.elc | Bin 0 -> 10602 bytes xemacs-packages/lisp/xemacs-base/env.el | 149 + xemacs-packages/lisp/xemacs-base/env.elc | Bin 0 -> 3312 bytes xemacs-packages/lisp/xemacs-base/facemenu.el | 878 ++ xemacs-packages/lisp/xemacs-base/facemenu.elc | Bin 0 -> 22130 bytes xemacs-packages/lisp/xemacs-base/ffap.el | 1732 +++ xemacs-packages/lisp/xemacs-base/ffap.elc | Bin 0 -> 37683 bytes xemacs-packages/lisp/xemacs-base/field.el | 297 + xemacs-packages/lisp/xemacs-base/field.elc | Bin 0 -> 6879 bytes xemacs-packages/lisp/xemacs-base/helper.el | 159 + xemacs-packages/lisp/xemacs-base/helper.elc | Bin 0 -> 3260 bytes xemacs-packages/lisp/xemacs-base/imenu.el | 1031 ++ xemacs-packages/lisp/xemacs-base/imenu.elc | Bin 0 -> 21900 bytes .../lisp/xemacs-base/iso-syntax.el | 38 + .../lisp/xemacs-base/iso-syntax.elc | Bin 0 -> 669 bytes xemacs-packages/lisp/xemacs-base/macros.el | 242 + xemacs-packages/lisp/xemacs-base/macros.elc | Bin 0 -> 5791 bytes xemacs-packages/lisp/xemacs-base/novice.el | 168 + xemacs-packages/lisp/xemacs-base/novice.elc | Bin 0 -> 2858 bytes xemacs-packages/lisp/xemacs-base/outline.el | 649 + xemacs-packages/lisp/xemacs-base/outline.elc | Bin 0 -> 16150 bytes xemacs-packages/lisp/xemacs-base/passwd.el | 403 + xemacs-packages/lisp/xemacs-base/passwd.elc | Bin 0 -> 8572 bytes xemacs-packages/lisp/xemacs-base/pp.el | 193 + xemacs-packages/lisp/xemacs-base/pp.elc | Bin 0 -> 3398 bytes .../lisp/xemacs-base/regexp-opt.el | 278 + .../lisp/xemacs-base/regexp-opt.elc | Bin 0 -> 4118 bytes xemacs-packages/lisp/xemacs-base/regi.el | 259 + xemacs-packages/lisp/xemacs-base/regi.elc | Bin 0 -> 5802 bytes xemacs-packages/lisp/xemacs-base/ring.el | 172 + xemacs-packages/lisp/xemacs-base/ring.elc | Bin 0 -> 3582 bytes xemacs-packages/lisp/xemacs-base/shell.el | 1198 ++ xemacs-packages/lisp/xemacs-base/shell.elc | Bin 0 -> 32025 bytes xemacs-packages/lisp/xemacs-base/skeleton.el | 591 + xemacs-packages/lisp/xemacs-base/skeleton.elc | Bin 0 -> 15828 bytes xemacs-packages/lisp/xemacs-base/sort.el | 624 + xemacs-packages/lisp/xemacs-base/sort.elc | Bin 0 -> 14117 bytes xemacs-packages/lisp/xemacs-base/thing.el | 350 + xemacs-packages/lisp/xemacs-base/thing.elc | Bin 0 -> 6918 bytes .../lisp/xemacs-base/time-stamp.el | 541 + .../lisp/xemacs-base/time-stamp.elc | Bin 0 -> 11917 bytes .../lisp/xemacs-base/timer-funcs.el | 291 + .../lisp/xemacs-base/timer-funcs.elc | Bin 0 -> 7650 bytes xemacs-packages/lisp/xemacs-base/timezone.el | 430 + xemacs-packages/lisp/xemacs-base/timezone.elc | Bin 0 -> 10187 bytes xemacs-packages/lisp/xemacs-base/tq.el | 124 + xemacs-packages/lisp/xemacs-base/tq.elc | Bin 0 -> 3048 bytes .../lisp/xemacs-base/xbm-button.el | 335 + .../lisp/xemacs-base/xbm-button.elc | Bin 0 -> 14653 bytes .../lisp/xemacs-base/xpm-button.el | 415 + .../lisp/xemacs-base/xpm-button.elc | Bin 0 -> 15645 bytes xemacs-packages/lisp/xemacs-devel/ChangeLog | 821 ++ xemacs-packages/lisp/xemacs-devel/_pkg.el | 5 + .../lisp/xemacs-devel/auto-autoloads.el | 582 + .../lisp/xemacs-devel/auto-autoloads.elc | Bin 0 -> 25928 bytes xemacs-packages/lisp/xemacs-devel/bench.el | 540 + xemacs-packages/lisp/xemacs-devel/bench.elc | Bin 0 -> 13081 bytes xemacs-packages/lisp/xemacs-devel/checkdoc.el | 2762 ++++ .../lisp/xemacs-devel/checkdoc.elc | Bin 0 -> 56653 bytes .../lisp/xemacs-devel/custom-load.el | 24 + .../lisp/xemacs-devel/custom-load.elc | Bin 0 -> 1168 bytes xemacs-packages/lisp/xemacs-devel/docref.el | 287 + xemacs-packages/lisp/xemacs-devel/docref.elc | Bin 0 -> 5954 bytes xemacs-packages/lisp/xemacs-devel/eldoc.el | 662 + xemacs-packages/lisp/xemacs-devel/eldoc.elc | Bin 0 -> 11129 bytes xemacs-packages/lisp/xemacs-devel/elp.el | 608 + xemacs-packages/lisp/xemacs-devel/elp.elc | Bin 0 -> 10450 bytes .../lisp/xemacs-devel/eval-expr.el | 262 + .../lisp/xemacs-devel/eval-expr.elc | Bin 0 -> 4745 bytes .../lisp/xemacs-devel/find-func.el | 403 + .../lisp/xemacs-devel/find-func.elc | Bin 0 -> 10108 bytes xemacs-packages/lisp/xemacs-devel/find-gc.el | 160 + xemacs-packages/lisp/xemacs-devel/find-gc.elc | Bin 0 -> 2676 bytes .../lisp/xemacs-devel/hide-copyleft.el | 161 + .../lisp/xemacs-devel/hide-copyleft.elc | Bin 0 -> 2952 bytes xemacs-packages/lisp/xemacs-devel/ielm.el | 493 + xemacs-packages/lisp/xemacs-devel/ielm.elc | Bin 0 -> 10927 bytes .../lisp/xemacs-devel/lisp-file-db.el | 39 + .../lisp/xemacs-devel/lisp-file-db.elc | Bin 0 -> 1740 bytes .../lisp/xemacs-devel/patch-keywords.el | 317 + .../lisp/xemacs-devel/patch-keywords.elc | Bin 0 -> 5842 bytes xemacs-packages/lisp/xemacs-devel/patcher.el | 3423 +++++ xemacs-packages/lisp/xemacs-devel/patcher.elc | Bin 0 -> 87595 bytes .../lisp/xemacs-devel/pretty-print.el | 577 + .../lisp/xemacs-devel/pretty-print.elc | Bin 0 -> 9658 bytes xemacs-packages/lisp/xemacs-devel/profile.el | 416 + xemacs-packages/lisp/xemacs-devel/profile.elc | Bin 0 -> 11570 bytes .../lisp/xemacs-devel/reposition.el | 202 + .../lisp/xemacs-devel/reposition.elc | Bin 0 -> 2559 bytes xemacs-packages/lisp/xemacs-devel/trace.el | 331 + xemacs-packages/lisp/xemacs-devel/trace.elc | Bin 0 -> 5090 bytes xemacs-packages/man/bbdb/bbdb.texinfo | 3978 ++++++ xemacs-packages/man/ediff/ediff.texi | 2530 ++++ .../man/edit-utils/edit-utils.texi | 3969 ++++++ xemacs-packages/man/edit-utils/tempo.texi | 599 + xemacs-packages/man/mail-lib/smtpmail.texi | 412 + xemacs-packages/man/os-utils/os-utils.texi | 826 ++ xemacs-packages/man/pgg/pgg.texi | 399 + .../man/prog-modes/prog-modes.texi | 2625 ++++ .../man/re-builder/re-builder.texi | 287 + xemacs-packages/man/speedbar/speedbar.texi | 1296 ++ xemacs-packages/man/tramp/tramp.texi | 2405 ++++ xemacs-packages/man/tramp/tramp_ja.texi | 2172 +++ xemacs-packages/man/xemacs-devel/patcher.texi | 2000 +++ xemacs-packages/pkginfo/MANIFEST.bbdb | 59 + xemacs-packages/pkginfo/MANIFEST.c-support | 21 + xemacs-packages/pkginfo/MANIFEST.ecrypto | 37 + xemacs-packages/pkginfo/MANIFEST.ediff | 58 + xemacs-packages/pkginfo/MANIFEST.edit-utils | 147 + xemacs-packages/pkginfo/MANIFEST.mail-lib | 47 + xemacs-packages/pkginfo/MANIFEST.net-utils | 37 + xemacs-packages/pkginfo/MANIFEST.os-utils | 41 + xemacs-packages/pkginfo/MANIFEST.perl-modes | 11 + xemacs-packages/pkginfo/MANIFEST.pgg | 22 + xemacs-packages/pkginfo/MANIFEST.prog-modes | 69 + xemacs-packages/pkginfo/MANIFEST.python-modes | 13 + xemacs-packages/pkginfo/MANIFEST.re-builder | 11 + xemacs-packages/pkginfo/MANIFEST.sh-script | 11 + xemacs-packages/pkginfo/MANIFEST.speedbar | 58 + xemacs-packages/pkginfo/MANIFEST.texinfo | 23 + xemacs-packages/pkginfo/MANIFEST.text-modes | 73 + xemacs-packages/pkginfo/MANIFEST.tramp | 30 + xemacs-packages/pkginfo/MANIFEST.xemacs-base | 92 + xemacs-packages/pkginfo/MANIFEST.xemacs-devel | 43 + 1046 files changed, 410159 insertions(+) create mode 100644 ac-dict/cfengine3-mode create mode 100644 centered-cursor-mode.el create mode 100644 centered-cursor-mode.elc create mode 100644 cfengine-code-style.el create mode 100644 cfengine-code-style.elc create mode 100644 cfengine.el create mode 100644 cfengine.elc create mode 100644 custom.el create mode 100644 egg-grep.el create mode 100644 egg-grep.elc create mode 100644 egg.el create mode 100644 egg.elc create mode 100644 init.el create mode 100644 template.el create mode 100644 template.elc create mode 100644 templates/DEFAULT.tpl create mode 100644 templates/Makefile.tpl create mode 100644 templates/README.tpl create mode 100644 templates/TEMPLATE.c.tpl create mode 100644 templates/TEMPLATE.cls.tpl create mode 100644 templates/TEMPLATE.el.tpl create mode 100644 templates/TEMPLATE.h.tpl create mode 100644 templates/TEMPLATE.html.tpl create mode 100644 templates/TEMPLATE.java.tpl create mode 100644 templates/TEMPLATE.pl.tpl create mode 100644 templates/TEMPLATE.sh.tpl create mode 100644 templates/TEMPLATE.sty.tpl create mode 100644 templates/TEMPLATE.tex.tpl create mode 100644 xemacs-bg.xpm create mode 100644 xemacs-packages/etc/bbdb/bbdb-213-310.el create mode 100644 xemacs-packages/etc/bbdb/bbdb-415-510.el create mode 100755 xemacs-packages/etc/bbdb/bbdb-areacode-split.pl create mode 100755 xemacs-packages/etc/bbdb/bbdb-cid.pl create mode 100755 xemacs-packages/etc/bbdb/bbdb-srv.pl create mode 100644 xemacs-packages/etc/bbdb/bbdb-to-netscape.el create mode 100755 xemacs-packages/etc/bbdb/bbdb-unlazy-lock.pl create mode 100644 xemacs-packages/etc/bbdb/tex/bbdb-cols.tex create mode 100644 xemacs-packages/etc/bbdb/tex/bbdb-print-brief.tex create mode 100644 xemacs-packages/etc/bbdb/tex/bbdb-print.tex create mode 100644 xemacs-packages/etc/ediff/ediff-A-up.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-A-up.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-A-xx.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-B-up.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-B-up.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-B-xx.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-help.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-help.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-next.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-next.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-prev.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-prev.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-quit.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-quit.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-refine.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-refine.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-save-xx.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-save-xx.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-save.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-save.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-toggle-split-up.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-toggle-split-up.xpm create mode 100644 xemacs-packages/etc/ediff/ediff-update.xbm create mode 100644 xemacs-packages/etc/ediff/ediff-update.xpm create mode 100644 xemacs-packages/etc/enriched.doc create mode 100755 xemacs-packages/etc/python-modes/pydoc_lisp.py create mode 100644 xemacs-packages/info/bbdb.info create mode 100644 xemacs-packages/info/ediff.info create mode 100644 xemacs-packages/info/edit-utils.info create mode 100644 xemacs-packages/info/os-utils.info create mode 100644 xemacs-packages/info/patcher.info create mode 100644 xemacs-packages/info/pgg.info create mode 100644 xemacs-packages/info/prog-modes.info create mode 100644 xemacs-packages/info/re-builder.info create mode 100644 xemacs-packages/info/smtpmail.info create mode 100644 xemacs-packages/info/speedbar.info create mode 100644 xemacs-packages/info/tempo.info create mode 100644 xemacs-packages/info/tramp.info create mode 100644 xemacs-packages/info/tramp_ja.info create mode 100644 xemacs-packages/lisp/bbdb/ChangeLog create mode 100644 xemacs-packages/lisp/bbdb/INSTALL create mode 100644 xemacs-packages/lisp/bbdb/README create mode 100644 xemacs-packages/lisp/bbdb/_pkg.el create mode 100644 xemacs-packages/lisp/bbdb/auto-autoloads.el create mode 100644 xemacs-packages/lisp/bbdb/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-com.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-com.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-ftp.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-ftp.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-gnus.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-gnus.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-gui.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-gui.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-hooks.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-hooks.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-merge.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-merge.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-mhe.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-mhe.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-migrate.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-migrate.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-print.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-print.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-reportmail.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-reportmail.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-rmail.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-rmail.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-sc.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-sc.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-snarf.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-snarf.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-srv.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-srv.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-vm.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-vm.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-w3.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-w3.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-whois.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-whois.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb-xemacs.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb-xemacs.elc create mode 100644 xemacs-packages/lisp/bbdb/bbdb.el create mode 100644 xemacs-packages/lisp/bbdb/bbdb.elc create mode 100644 xemacs-packages/lisp/bbdb/custom-load.el create mode 100644 xemacs-packages/lisp/bbdb/custom-load.elc create mode 100644 xemacs-packages/lisp/c-support/ChangeLog create mode 100644 xemacs-packages/lisp/c-support/_pkg.el create mode 100644 xemacs-packages/lisp/c-support/auto-autoloads.el create mode 100644 xemacs-packages/lisp/c-support/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/c-support/c-comment-edit.el create mode 100644 xemacs-packages/lisp/c-support/c-comment-edit.elc create mode 100644 xemacs-packages/lisp/c-support/c-fill.el create mode 100644 xemacs-packages/lisp/c-support/c-fill.elc create mode 100644 xemacs-packages/lisp/c-support/c-style.el create mode 100644 xemacs-packages/lisp/c-support/c-style.elc create mode 100644 xemacs-packages/lisp/c-support/cmacexp.el create mode 100644 xemacs-packages/lisp/c-support/cmacexp.elc create mode 100644 xemacs-packages/lisp/c-support/ctypes.el create mode 100644 xemacs-packages/lisp/c-support/ctypes.elc create mode 100644 xemacs-packages/lisp/c-support/custom-load.el create mode 100644 xemacs-packages/lisp/c-support/custom-load.elc create mode 100644 xemacs-packages/lisp/c-support/hideif.el create mode 100644 xemacs-packages/lisp/c-support/hideif.elc create mode 100644 xemacs-packages/lisp/c-support/hideshow.el create mode 100644 xemacs-packages/lisp/c-support/hideshow.elc create mode 100644 xemacs-packages/lisp/ecrypto/ChangeLog create mode 100644 xemacs-packages/lisp/ecrypto/_pkg.el create mode 100644 xemacs-packages/lisp/ecrypto/ascii-armor.el create mode 100644 xemacs-packages/lisp/ecrypto/ascii-armor.elc create mode 100644 xemacs-packages/lisp/ecrypto/auto-autoloads.el create mode 100644 xemacs-packages/lisp/ecrypto/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/ecrypto/blowfish.el create mode 100644 xemacs-packages/lisp/ecrypto/blowfish.elc create mode 100644 xemacs-packages/lisp/ecrypto/custom-load.el create mode 100644 xemacs-packages/lisp/ecrypto/custom-load.elc create mode 100644 xemacs-packages/lisp/ecrypto/des.el create mode 100644 xemacs-packages/lisp/ecrypto/des.elc create mode 100644 xemacs-packages/lisp/ecrypto/encrypt.el create mode 100644 xemacs-packages/lisp/ecrypto/encrypt.elc create mode 100644 xemacs-packages/lisp/ecrypto/hex-util.el create mode 100644 xemacs-packages/lisp/ecrypto/hex-util.elc create mode 100644 xemacs-packages/lisp/ecrypto/md4.el create mode 100644 xemacs-packages/lisp/ecrypto/md4.elc create mode 100644 xemacs-packages/lisp/ecrypto/md5-dl.el create mode 100644 xemacs-packages/lisp/ecrypto/md5-dl.elc create mode 100644 xemacs-packages/lisp/ecrypto/md5-el.el create mode 100644 xemacs-packages/lisp/ecrypto/md5-el.elc create mode 100644 xemacs-packages/lisp/ecrypto/md5.el create mode 100644 xemacs-packages/lisp/ecrypto/md5.elc create mode 100644 xemacs-packages/lisp/ecrypto/paranoid.el create mode 100644 xemacs-packages/lisp/ecrypto/paranoid.elc create mode 100644 xemacs-packages/lisp/ecrypto/password.el create mode 100644 xemacs-packages/lisp/ecrypto/password.elc create mode 100644 xemacs-packages/lisp/ecrypto/rander.el create mode 100644 xemacs-packages/lisp/ecrypto/rander.elc create mode 100644 xemacs-packages/lisp/ecrypto/rc16.el create mode 100644 xemacs-packages/lisp/ecrypto/rc16.elc create mode 100644 xemacs-packages/lisp/ecrypto/rijndael.el create mode 100644 xemacs-packages/lisp/ecrypto/rijndael.elc create mode 100644 xemacs-packages/lisp/ecrypto/sha1.el create mode 100644 xemacs-packages/lisp/ecrypto/sha1.elc create mode 100644 xemacs-packages/lisp/ediff/ChangeLog create mode 100644 xemacs-packages/lisp/ediff/README create mode 100644 xemacs-packages/lisp/ediff/_pkg.el create mode 100644 xemacs-packages/lisp/ediff/auto-autoloads.el create mode 100644 xemacs-packages/lisp/ediff/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/ediff/custom-load.el create mode 100644 xemacs-packages/lisp/ediff/custom-load.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-diff.el create mode 100644 xemacs-packages/lisp/ediff/ediff-diff.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-help.el create mode 100644 xemacs-packages/lisp/ediff/ediff-help.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-hook.el create mode 100644 xemacs-packages/lisp/ediff/ediff-hook.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-init.el create mode 100644 xemacs-packages/lisp/ediff/ediff-init.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-merg.el create mode 100644 xemacs-packages/lisp/ediff/ediff-merg.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-mult.el create mode 100644 xemacs-packages/lisp/ediff/ediff-mult.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-ptch.el create mode 100644 xemacs-packages/lisp/ediff/ediff-ptch.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-tbar.el create mode 100644 xemacs-packages/lisp/ediff/ediff-tbar.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-util.el create mode 100644 xemacs-packages/lisp/ediff/ediff-util.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-vers.el create mode 100644 xemacs-packages/lisp/ediff/ediff-vers.elc create mode 100644 xemacs-packages/lisp/ediff/ediff-wind.el create mode 100644 xemacs-packages/lisp/ediff/ediff-wind.elc create mode 100644 xemacs-packages/lisp/ediff/ediff.el create mode 100644 xemacs-packages/lisp/ediff/ediff.elc create mode 100644 xemacs-packages/lisp/edit-utils/ChangeLog create mode 100644 xemacs-packages/lisp/edit-utils/_pkg.el create mode 100644 xemacs-packages/lisp/edit-utils/abbrevlist.el create mode 100644 xemacs-packages/lisp/edit-utils/abbrevlist.elc create mode 100644 xemacs-packages/lisp/edit-utils/after-save-commands.el create mode 100644 xemacs-packages/lisp/edit-utils/after-save-commands.elc create mode 100644 xemacs-packages/lisp/edit-utils/align.el create mode 100644 xemacs-packages/lisp/edit-utils/align.elc create mode 100644 xemacs-packages/lisp/edit-utils/allout.el create mode 100644 xemacs-packages/lisp/edit-utils/allout.elc create mode 100644 xemacs-packages/lisp/edit-utils/array.el create mode 100644 xemacs-packages/lisp/edit-utils/array.elc create mode 100644 xemacs-packages/lisp/edit-utils/atomic-extents.el create mode 100644 xemacs-packages/lisp/edit-utils/atomic-extents.elc create mode 100644 xemacs-packages/lisp/edit-utils/auto-autoloads.el create mode 100644 xemacs-packages/lisp/edit-utils/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/edit-utils/autorevert.el create mode 100644 xemacs-packages/lisp/edit-utils/autorevert.elc create mode 100644 xemacs-packages/lisp/edit-utils/avoid.el create mode 100644 xemacs-packages/lisp/edit-utils/avoid.elc create mode 100644 xemacs-packages/lisp/edit-utils/backup-dir.el create mode 100644 xemacs-packages/lisp/edit-utils/backup-dir.elc create mode 100644 xemacs-packages/lisp/edit-utils/balloon-help.el create mode 100644 xemacs-packages/lisp/edit-utils/balloon-help.elc create mode 100644 xemacs-packages/lisp/edit-utils/big-menubar.el create mode 100644 xemacs-packages/lisp/edit-utils/big-menubar.elc create mode 100644 xemacs-packages/lisp/edit-utils/blink-cursor.el create mode 100644 xemacs-packages/lisp/edit-utils/blink-cursor.elc create mode 100644 xemacs-packages/lisp/edit-utils/blink-paren.el create mode 100644 xemacs-packages/lisp/edit-utils/blink-paren.elc create mode 100644 xemacs-packages/lisp/edit-utils/bookmark.el create mode 100644 xemacs-packages/lisp/edit-utils/bookmark.elc create mode 100644 xemacs-packages/lisp/edit-utils/compare-w.el create mode 100644 xemacs-packages/lisp/edit-utils/compare-w.elc create mode 100644 xemacs-packages/lisp/edit-utils/completion.el create mode 100644 xemacs-packages/lisp/edit-utils/completion.elc create mode 100755 xemacs-packages/lisp/edit-utils/crm.el create mode 100644 xemacs-packages/lisp/edit-utils/crm.elc create mode 100644 xemacs-packages/lisp/edit-utils/custom-load.el create mode 100644 xemacs-packages/lisp/edit-utils/custom-load.elc create mode 100644 xemacs-packages/lisp/edit-utils/dabbrev.el create mode 100644 xemacs-packages/lisp/edit-utils/dabbrev.elc create mode 100644 xemacs-packages/lisp/edit-utils/desktop.el create mode 100644 xemacs-packages/lisp/edit-utils/desktop.elc create mode 100644 xemacs-packages/lisp/edit-utils/detached-minibuf.el create mode 100644 xemacs-packages/lisp/edit-utils/detached-minibuf.elc create mode 100644 xemacs-packages/lisp/edit-utils/edit-faces.el create mode 100644 xemacs-packages/lisp/edit-utils/edit-faces.elc create mode 100644 xemacs-packages/lisp/edit-utils/edit-toolbar.el create mode 100644 xemacs-packages/lisp/edit-utils/edit-toolbar.elc create mode 100644 xemacs-packages/lisp/edit-utils/fast-lock.el create mode 100644 xemacs-packages/lisp/edit-utils/fast-lock.elc create mode 100644 xemacs-packages/lisp/edit-utils/file-part.el create mode 100644 xemacs-packages/lisp/edit-utils/file-part.elc create mode 100644 xemacs-packages/lisp/edit-utils/floating-toolbar.el create mode 100644 xemacs-packages/lisp/edit-utils/floating-toolbar.elc create mode 100644 xemacs-packages/lisp/edit-utils/flow-ctrl.el create mode 100644 xemacs-packages/lisp/edit-utils/flow-ctrl.elc create mode 100644 xemacs-packages/lisp/edit-utils/foldout.el create mode 100644 xemacs-packages/lisp/edit-utils/foldout.elc create mode 100644 xemacs-packages/lisp/edit-utils/func-menu.el create mode 100644 xemacs-packages/lisp/edit-utils/func-menu.elc create mode 100644 xemacs-packages/lisp/edit-utils/highline.el create mode 100644 xemacs-packages/lisp/edit-utils/highline.elc create mode 100644 xemacs-packages/lisp/edit-utils/hippie-exp.el create mode 100644 xemacs-packages/lisp/edit-utils/hippie-exp.elc create mode 100644 xemacs-packages/lisp/edit-utils/icomplete.el create mode 100644 xemacs-packages/lisp/edit-utils/icomplete.elc create mode 100644 xemacs-packages/lisp/edit-utils/id-select.el create mode 100644 xemacs-packages/lisp/edit-utils/id-select.elc create mode 100644 xemacs-packages/lisp/edit-utils/info-look.el create mode 100644 xemacs-packages/lisp/edit-utils/info-look.elc create mode 100644 xemacs-packages/lisp/edit-utils/iswitchb.el create mode 100644 xemacs-packages/lisp/edit-utils/iswitchb.elc create mode 100644 xemacs-packages/lisp/edit-utils/lazy-lock.el create mode 100644 xemacs-packages/lisp/edit-utils/lazy-lock.elc create mode 100644 xemacs-packages/lisp/edit-utils/lazy-shot.el create mode 100644 xemacs-packages/lisp/edit-utils/lazy-shot.elc create mode 100644 xemacs-packages/lisp/edit-utils/lispm-fonts.el create mode 100644 xemacs-packages/lisp/edit-utils/lispm-fonts.elc create mode 100644 xemacs-packages/lisp/edit-utils/live-icon.el create mode 100644 xemacs-packages/lisp/edit-utils/live-icon.elc create mode 100644 xemacs-packages/lisp/edit-utils/makesum.el create mode 100644 xemacs-packages/lisp/edit-utils/makesum.elc create mode 100644 xemacs-packages/lisp/edit-utils/man.el create mode 100644 xemacs-packages/lisp/edit-utils/man.elc create mode 100644 xemacs-packages/lisp/edit-utils/mic-paren.el create mode 100644 xemacs-packages/lisp/edit-utils/mic-paren.elc create mode 100644 xemacs-packages/lisp/edit-utils/mode-motion+.el create mode 100644 xemacs-packages/lisp/edit-utils/mode-motion+.elc create mode 100644 xemacs-packages/lisp/edit-utils/narrow-stack.el create mode 100644 xemacs-packages/lisp/edit-utils/narrow-stack.elc create mode 100644 xemacs-packages/lisp/edit-utils/outl-mouse.el create mode 100644 xemacs-packages/lisp/edit-utils/outl-mouse.elc create mode 100644 xemacs-packages/lisp/edit-utils/page-ext.el create mode 100644 xemacs-packages/lisp/edit-utils/page-ext.elc create mode 100644 xemacs-packages/lisp/edit-utils/paren.el create mode 100644 xemacs-packages/lisp/edit-utils/paren.elc create mode 100644 xemacs-packages/lisp/edit-utils/permanent-buffers.el create mode 100644 xemacs-packages/lisp/edit-utils/permanent-buffers.elc create mode 100644 xemacs-packages/lisp/edit-utils/popper.el create mode 100644 xemacs-packages/lisp/edit-utils/popper.elc create mode 100644 xemacs-packages/lisp/edit-utils/power-macros.el create mode 100644 xemacs-packages/lisp/edit-utils/power-macros.elc create mode 100644 xemacs-packages/lisp/edit-utils/recent-files.el create mode 100644 xemacs-packages/lisp/edit-utils/recent-files.elc create mode 100644 xemacs-packages/lisp/edit-utils/redo.el create mode 100644 xemacs-packages/lisp/edit-utils/redo.elc create mode 100644 xemacs-packages/lisp/edit-utils/reportmail.el create mode 100644 xemacs-packages/lisp/edit-utils/reportmail.elc create mode 100644 xemacs-packages/lisp/edit-utils/resume.el create mode 100644 xemacs-packages/lisp/edit-utils/resume.elc create mode 100644 xemacs-packages/lisp/edit-utils/rsz-minibuf.el create mode 100644 xemacs-packages/lisp/edit-utils/rsz-minibuf.elc create mode 100644 xemacs-packages/lisp/edit-utils/saveconf.el create mode 100644 xemacs-packages/lisp/edit-utils/saveconf.elc create mode 100644 xemacs-packages/lisp/edit-utils/savehist.el create mode 100644 xemacs-packages/lisp/edit-utils/savehist.elc create mode 100644 xemacs-packages/lisp/edit-utils/saveplace.el create mode 100644 xemacs-packages/lisp/edit-utils/saveplace.elc create mode 100644 xemacs-packages/lisp/edit-utils/scroll-in-place.el create mode 100644 xemacs-packages/lisp/edit-utils/scroll-in-place.elc create mode 100644 xemacs-packages/lisp/edit-utils/search-buffers.el create mode 100644 xemacs-packages/lisp/edit-utils/search-buffers.elc create mode 100644 xemacs-packages/lisp/edit-utils/setnu.el create mode 100644 xemacs-packages/lisp/edit-utils/setnu.elc create mode 100644 xemacs-packages/lisp/edit-utils/shell-font.el create mode 100644 xemacs-packages/lisp/edit-utils/shell-font.elc create mode 100644 xemacs-packages/lisp/edit-utils/tempo.el create mode 100644 xemacs-packages/lisp/edit-utils/tempo.elc create mode 100644 xemacs-packages/lisp/edit-utils/toolbar-utils.el create mode 100644 xemacs-packages/lisp/edit-utils/toolbar-utils.elc create mode 100644 xemacs-packages/lisp/edit-utils/tree-menu.el create mode 100644 xemacs-packages/lisp/edit-utils/tree-menu.elc create mode 100644 xemacs-packages/lisp/edit-utils/uniquify.el create mode 100644 xemacs-packages/lisp/edit-utils/uniquify.elc create mode 100644 xemacs-packages/lisp/edit-utils/vertical-mode.el create mode 100644 xemacs-packages/lisp/edit-utils/vertical-mode.elc create mode 100644 xemacs-packages/lisp/edit-utils/where-was-i-db.el create mode 100644 xemacs-packages/lisp/edit-utils/where-was-i-db.elc create mode 100644 xemacs-packages/lisp/edit-utils/winring.el create mode 100644 xemacs-packages/lisp/edit-utils/winring.elc create mode 100644 xemacs-packages/lisp/mail-lib/ChangeLog create mode 100644 xemacs-packages/lisp/mail-lib/_pkg.el create mode 100644 xemacs-packages/lisp/mail-lib/auto-autoloads.el create mode 100644 xemacs-packages/lisp/mail-lib/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/mail-lib/base64.el create mode 100644 xemacs-packages/lisp/mail-lib/base64.elc create mode 100644 xemacs-packages/lisp/mail-lib/browse-url-xemacs.el create mode 100644 xemacs-packages/lisp/mail-lib/browse-url-xemacs.elc create mode 100644 xemacs-packages/lisp/mail-lib/browse-url.el create mode 100644 xemacs-packages/lisp/mail-lib/browse-url.elc create mode 100644 xemacs-packages/lisp/mail-lib/custom-load.el create mode 100644 xemacs-packages/lisp/mail-lib/custom-load.elc create mode 100644 xemacs-packages/lisp/mail-lib/highlight-headers.el create mode 100644 xemacs-packages/lisp/mail-lib/highlight-headers.elc create mode 100644 xemacs-packages/lisp/mail-lib/mail-abbrevs.el create mode 100644 xemacs-packages/lisp/mail-lib/mail-abbrevs.elc create mode 100644 xemacs-packages/lisp/mail-lib/mail-extr.el create mode 100644 xemacs-packages/lisp/mail-lib/mail-extr.elc create mode 100644 xemacs-packages/lisp/mail-lib/mail-utils.el create mode 100644 xemacs-packages/lisp/mail-lib/mail-utils.elc create mode 100644 xemacs-packages/lisp/mail-lib/mailheader.el create mode 100644 xemacs-packages/lisp/mail-lib/mailheader.elc create mode 100644 xemacs-packages/lisp/mail-lib/netrc.el create mode 100644 xemacs-packages/lisp/mail-lib/netrc.elc create mode 100644 xemacs-packages/lisp/mail-lib/pop3.el create mode 100644 xemacs-packages/lisp/mail-lib/pop3.elc create mode 100644 xemacs-packages/lisp/mail-lib/reporter.el create mode 100644 xemacs-packages/lisp/mail-lib/reporter.elc create mode 100644 xemacs-packages/lisp/mail-lib/rfc2104.el create mode 100644 xemacs-packages/lisp/mail-lib/rfc2104.elc create mode 100644 xemacs-packages/lisp/mail-lib/rfc822.el create mode 100644 xemacs-packages/lisp/mail-lib/rfc822.elc create mode 100644 xemacs-packages/lisp/mail-lib/rmail-mini.el create mode 100644 xemacs-packages/lisp/mail-lib/rmail-mini.elc create mode 100644 xemacs-packages/lisp/mail-lib/rmailout.el create mode 100644 xemacs-packages/lisp/mail-lib/rmailout.elc create mode 100644 xemacs-packages/lisp/mail-lib/sendmail.el create mode 100644 xemacs-packages/lisp/mail-lib/sendmail.elc create mode 100644 xemacs-packages/lisp/mail-lib/smtpmail.el create mode 100644 xemacs-packages/lisp/mail-lib/smtpmail.elc create mode 100644 xemacs-packages/lisp/mail-lib/starttls.el create mode 100644 xemacs-packages/lisp/mail-lib/starttls.elc create mode 100644 xemacs-packages/lisp/mail-lib/tls.el create mode 100644 xemacs-packages/lisp/mail-lib/tls.elc create mode 100644 xemacs-packages/lisp/net-utils/ChangeLog create mode 100644 xemacs-packages/lisp/net-utils/_pkg.el create mode 100644 xemacs-packages/lisp/net-utils/auto-autoloads.el create mode 100644 xemacs-packages/lisp/net-utils/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/net-utils/browse-cltl2.el create mode 100644 xemacs-packages/lisp/net-utils/browse-cltl2.elc create mode 100644 xemacs-packages/lisp/net-utils/custom-load.el create mode 100644 xemacs-packages/lisp/net-utils/custom-load.elc create mode 100644 xemacs-packages/lisp/net-utils/dig.el create mode 100644 xemacs-packages/lisp/net-utils/dig.elc create mode 100644 xemacs-packages/lisp/net-utils/dns-mode.el create mode 100644 xemacs-packages/lisp/net-utils/dns-mode.elc create mode 100644 xemacs-packages/lisp/net-utils/dns.el create mode 100644 xemacs-packages/lisp/net-utils/dns.elc create mode 100644 xemacs-packages/lisp/net-utils/feedmail.el create mode 100644 xemacs-packages/lisp/net-utils/feedmail.elc create mode 100644 xemacs-packages/lisp/net-utils/google-query.el create mode 100644 xemacs-packages/lisp/net-utils/google-query.elc create mode 100644 xemacs-packages/lisp/net-utils/metamail.el create mode 100644 xemacs-packages/lisp/net-utils/metamail.elc create mode 100644 xemacs-packages/lisp/net-utils/mozmail.el create mode 100644 xemacs-packages/lisp/net-utils/mozmail.elc create mode 100644 xemacs-packages/lisp/net-utils/net-utils.el create mode 100644 xemacs-packages/lisp/net-utils/net-utils.elc create mode 100644 xemacs-packages/lisp/net-utils/rcompile.el create mode 100644 xemacs-packages/lisp/net-utils/rcompile.elc create mode 100644 xemacs-packages/lisp/net-utils/shadowfile.el create mode 100644 xemacs-packages/lisp/net-utils/shadowfile.elc create mode 100644 xemacs-packages/lisp/net-utils/webjump.el create mode 100644 xemacs-packages/lisp/net-utils/webjump.elc create mode 100644 xemacs-packages/lisp/net-utils/webster-www.el create mode 100644 xemacs-packages/lisp/net-utils/webster-www.elc create mode 100644 xemacs-packages/lisp/net-utils/xemacsbug.el create mode 100644 xemacs-packages/lisp/net-utils/xemacsbug.elc create mode 100644 xemacs-packages/lisp/net-utils/xml.el create mode 100644 xemacs-packages/lisp/net-utils/xml.elc create mode 100644 xemacs-packages/lisp/os-utils/ChangeLog create mode 100644 xemacs-packages/lisp/os-utils/_pkg.el create mode 100644 xemacs-packages/lisp/os-utils/arc-mode.el create mode 100644 xemacs-packages/lisp/os-utils/arc-mode.elc create mode 100644 xemacs-packages/lisp/os-utils/auto-autoloads.el create mode 100644 xemacs-packages/lisp/os-utils/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/os-utils/background.el create mode 100644 xemacs-packages/lisp/os-utils/background.elc create mode 100644 xemacs-packages/lisp/os-utils/crypt.el create mode 100644 xemacs-packages/lisp/os-utils/crypt.elc create mode 100644 xemacs-packages/lisp/os-utils/custom-load.el create mode 100644 xemacs-packages/lisp/os-utils/custom-load.elc create mode 100644 xemacs-packages/lisp/os-utils/ftelnet.el create mode 100644 xemacs-packages/lisp/os-utils/ftelnet.elc create mode 100644 xemacs-packages/lisp/os-utils/inf-lisp.el create mode 100644 xemacs-packages/lisp/os-utils/inf-lisp.elc create mode 100644 xemacs-packages/lisp/os-utils/jka-compr.el create mode 100644 xemacs-packages/lisp/os-utils/jka-compr.elc create mode 100644 xemacs-packages/lisp/os-utils/kermit.el create mode 100644 xemacs-packages/lisp/os-utils/kermit.elc create mode 100644 xemacs-packages/lisp/os-utils/ledit.el create mode 100644 xemacs-packages/lisp/os-utils/ledit.elc create mode 100644 xemacs-packages/lisp/os-utils/mchat.el create mode 100644 xemacs-packages/lisp/os-utils/mchat.elc create mode 100644 xemacs-packages/lisp/os-utils/rlogin.el create mode 100644 xemacs-packages/lisp/os-utils/rlogin.elc create mode 100644 xemacs-packages/lisp/os-utils/spell.el create mode 100644 xemacs-packages/lisp/os-utils/spell.elc create mode 100644 xemacs-packages/lisp/os-utils/ssh.el create mode 100644 xemacs-packages/lisp/os-utils/ssh.elc create mode 100644 xemacs-packages/lisp/os-utils/tar-mode.el create mode 100644 xemacs-packages/lisp/os-utils/tar-mode.elc create mode 100644 xemacs-packages/lisp/os-utils/telnet.el create mode 100644 xemacs-packages/lisp/os-utils/telnet.elc create mode 100644 xemacs-packages/lisp/os-utils/terminal.el create mode 100644 xemacs-packages/lisp/os-utils/terminal.elc create mode 100644 xemacs-packages/lisp/os-utils/uncompress.el create mode 100644 xemacs-packages/lisp/os-utils/uncompress.elc create mode 100644 xemacs-packages/lisp/perl-modes/ChangeLog create mode 100644 xemacs-packages/lisp/perl-modes/_pkg.el create mode 100644 xemacs-packages/lisp/perl-modes/auto-autoloads.el create mode 100644 xemacs-packages/lisp/perl-modes/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/perl-modes/cperl-mode.el create mode 100644 xemacs-packages/lisp/perl-modes/cperl-mode.elc create mode 100644 xemacs-packages/lisp/perl-modes/custom-load.el create mode 100644 xemacs-packages/lisp/perl-modes/custom-load.elc create mode 100644 xemacs-packages/lisp/perl-modes/perl-mode.el create mode 100644 xemacs-packages/lisp/perl-modes/perl-mode.elc create mode 100644 xemacs-packages/lisp/pgg/ChangeLog create mode 100644 xemacs-packages/lisp/pgg/README create mode 100644 xemacs-packages/lisp/pgg/_pkg.el create mode 100644 xemacs-packages/lisp/pgg/auto-autoloads.el create mode 100644 xemacs-packages/lisp/pgg/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/pgg/custom-load.el create mode 100644 xemacs-packages/lisp/pgg/custom-load.elc create mode 100644 xemacs-packages/lisp/pgg/pgg-def.el create mode 100644 xemacs-packages/lisp/pgg/pgg-def.elc create mode 100644 xemacs-packages/lisp/pgg/pgg-gpg.el create mode 100644 xemacs-packages/lisp/pgg/pgg-gpg.elc create mode 100644 xemacs-packages/lisp/pgg/pgg-parse.el create mode 100644 xemacs-packages/lisp/pgg/pgg-parse.elc create mode 100644 xemacs-packages/lisp/pgg/pgg-pgp.el create mode 100644 xemacs-packages/lisp/pgg/pgg-pgp.elc create mode 100644 xemacs-packages/lisp/pgg/pgg-pgp5.el create mode 100644 xemacs-packages/lisp/pgg/pgg-pgp5.elc create mode 100644 xemacs-packages/lisp/pgg/pgg.el create mode 100644 xemacs-packages/lisp/pgg/pgg.elc create mode 100644 xemacs-packages/lisp/prog-modes/ChangeLog create mode 100644 xemacs-packages/lisp/prog-modes/_pkg.el create mode 100644 xemacs-packages/lisp/prog-modes/asm-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/asm-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/auto-autoloads.el create mode 100644 xemacs-packages/lisp/prog-modes/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/prog-modes/autoconf-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/autoconf-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/awk-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/awk-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/cl-indent.el create mode 100644 xemacs-packages/lisp/prog-modes/cl-indent.elc create mode 100644 xemacs-packages/lisp/prog-modes/custom-load.el create mode 100644 xemacs-packages/lisp/prog-modes/custom-load.elc create mode 100644 xemacs-packages/lisp/prog-modes/cvs.el create mode 100644 xemacs-packages/lisp/prog-modes/cvs.elc create mode 100644 xemacs-packages/lisp/prog-modes/diff-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/diff-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/eiffel.el create mode 100644 xemacs-packages/lisp/prog-modes/eiffel.elc create mode 100644 xemacs-packages/lisp/prog-modes/icon.el create mode 100644 xemacs-packages/lisp/prog-modes/icon.elc create mode 100644 xemacs-packages/lisp/prog-modes/javascript-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/javascript-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/ksh-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/ksh-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/lua-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/lua-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/m4-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/m4-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/make-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/make-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/mode-compile.el create mode 100644 xemacs-packages/lisp/prog-modes/mode-compile.elc create mode 100644 xemacs-packages/lisp/prog-modes/modula2.el create mode 100644 xemacs-packages/lisp/prog-modes/modula2.elc create mode 100644 xemacs-packages/lisp/prog-modes/old-c-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/old-c-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/p4.el create mode 100644 xemacs-packages/lisp/prog-modes/p4.elc create mode 100644 xemacs-packages/lisp/prog-modes/pascal.el create mode 100644 xemacs-packages/lisp/prog-modes/pascal.elc create mode 100644 xemacs-packages/lisp/prog-modes/php-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/php-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/postscript.el create mode 100644 xemacs-packages/lisp/prog-modes/postscript.elc create mode 100644 xemacs-packages/lisp/prog-modes/prolog.el create mode 100644 xemacs-packages/lisp/prog-modes/prolog.elc create mode 100644 xemacs-packages/lisp/prog-modes/rexx-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/rexx-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/rpm-spec-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/rpm-spec-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/simula.el create mode 100644 xemacs-packages/lisp/prog-modes/simula.elc create mode 100644 xemacs-packages/lisp/prog-modes/sql.el create mode 100644 xemacs-packages/lisp/prog-modes/sql.elc create mode 100644 xemacs-packages/lisp/prog-modes/tcl.el create mode 100644 xemacs-packages/lisp/prog-modes/tcl.elc create mode 100644 xemacs-packages/lisp/prog-modes/teco.el create mode 100644 xemacs-packages/lisp/prog-modes/teco.elc create mode 100644 xemacs-packages/lisp/prog-modes/uil-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/uil-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/verilog-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/verilog-mode.elc create mode 100644 xemacs-packages/lisp/prog-modes/vrml-mode.el create mode 100644 xemacs-packages/lisp/prog-modes/vrml-mode.elc create mode 100644 xemacs-packages/lisp/python-modes/ChangeLog create mode 100644 xemacs-packages/lisp/python-modes/_pkg.el create mode 100644 xemacs-packages/lisp/python-modes/auto-autoloads.el create mode 100644 xemacs-packages/lisp/python-modes/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/python-modes/custom-load.el create mode 100644 xemacs-packages/lisp/python-modes/custom-load.elc create mode 100644 xemacs-packages/lisp/python-modes/pydoc-el-README create mode 100644 xemacs-packages/lisp/python-modes/pydoc.el create mode 100644 xemacs-packages/lisp/python-modes/pydoc.elc create mode 100644 xemacs-packages/lisp/python-modes/python-mode.el create mode 100644 xemacs-packages/lisp/python-modes/python-mode.elc create mode 100644 xemacs-packages/lisp/re-builder/ChangeLog create mode 100644 xemacs-packages/lisp/re-builder/_pkg.el create mode 100644 xemacs-packages/lisp/re-builder/auto-autoloads.el create mode 100644 xemacs-packages/lisp/re-builder/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/re-builder/custom-load.el create mode 100644 xemacs-packages/lisp/re-builder/custom-load.elc create mode 100644 xemacs-packages/lisp/re-builder/re-builder.el create mode 100644 xemacs-packages/lisp/re-builder/re-builder.elc create mode 100644 xemacs-packages/lisp/sh-script/ChangeLog create mode 100644 xemacs-packages/lisp/sh-script/_pkg.el create mode 100644 xemacs-packages/lisp/sh-script/auto-autoloads.el create mode 100644 xemacs-packages/lisp/sh-script/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/sh-script/custom-load.el create mode 100644 xemacs-packages/lisp/sh-script/custom-load.elc create mode 100644 xemacs-packages/lisp/sh-script/executable.el create mode 100644 xemacs-packages/lisp/sh-script/executable.elc create mode 100644 xemacs-packages/lisp/sh-script/sh-script.el create mode 100644 xemacs-packages/lisp/sh-script/sh-script.elc create mode 100644 xemacs-packages/lisp/speedbar/ChangeLog create mode 100644 xemacs-packages/lisp/speedbar/_pkg.el create mode 100644 xemacs-packages/lisp/speedbar/auto-autoloads.el create mode 100644 xemacs-packages/lisp/speedbar/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/speedbar/bigclock.el create mode 100644 xemacs-packages/lisp/speedbar/bigclock.elc create mode 100644 xemacs-packages/lisp/speedbar/custom-load.el create mode 100644 xemacs-packages/lisp/speedbar/custom-load.elc create mode 100644 xemacs-packages/lisp/speedbar/dframe.el create mode 100644 xemacs-packages/lisp/speedbar/dframe.elc create mode 100644 xemacs-packages/lisp/speedbar/rpm.el create mode 100644 xemacs-packages/lisp/speedbar/rpm.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-ant.el create mode 100644 xemacs-packages/lisp/speedbar/sb-ant.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-box-minus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-box-plus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-box.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-chk.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-dir-minus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-dir-plus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-dir.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-doc-minus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-doc-plus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-doc.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-gud.el create mode 100644 xemacs-packages/lisp/speedbar/sb-gud.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-html.el create mode 100644 xemacs-packages/lisp/speedbar/sb-html.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-image.el create mode 100644 xemacs-packages/lisp/speedbar/sb-image.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-info.el create mode 100644 xemacs-packages/lisp/speedbar/sb-info.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-info.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-label.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-mail.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-obj.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-objod.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-pg-minus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-pg-plus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-pg.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-rmail.el create mode 100644 xemacs-packages/lisp/speedbar/sb-rmail.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-ro.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag-gt.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag-minus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag-plus.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag-type.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag-v.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-tag.xpm create mode 100644 xemacs-packages/lisp/speedbar/sb-texinfo.el create mode 100644 xemacs-packages/lisp/speedbar/sb-texinfo.elc create mode 100644 xemacs-packages/lisp/speedbar/sb-w3.el create mode 100644 xemacs-packages/lisp/speedbar/sb-w3.elc create mode 100644 xemacs-packages/lisp/speedbar/speedbar.el create mode 100644 xemacs-packages/lisp/speedbar/speedbar.elc create mode 100644 xemacs-packages/lisp/template/ChangeLog create mode 100644 xemacs-packages/lisp/template/template.el create mode 100644 xemacs-packages/lisp/template/template.elc create mode 100644 xemacs-packages/lisp/texinfo/ChangeLog create mode 100644 xemacs-packages/lisp/texinfo/_pkg.el create mode 100644 xemacs-packages/lisp/texinfo/auto-autoloads.el create mode 100644 xemacs-packages/lisp/texinfo/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/texinfo/custom-load.el create mode 100644 xemacs-packages/lisp/texinfo/custom-load.elc create mode 100644 xemacs-packages/lisp/texinfo/detexinfo.el create mode 100644 xemacs-packages/lisp/texinfo/detexinfo.elc create mode 100644 xemacs-packages/lisp/texinfo/informat.el create mode 100644 xemacs-packages/lisp/texinfo/informat.elc create mode 100644 xemacs-packages/lisp/texinfo/makeinfo.el create mode 100644 xemacs-packages/lisp/texinfo/makeinfo.elc create mode 100644 xemacs-packages/lisp/texinfo/tex-mode.el create mode 100644 xemacs-packages/lisp/texinfo/tex-mode.elc create mode 100644 xemacs-packages/lisp/texinfo/texinfmt.el create mode 100644 xemacs-packages/lisp/texinfo/texinfmt.elc create mode 100644 xemacs-packages/lisp/texinfo/texinfo.el create mode 100644 xemacs-packages/lisp/texinfo/texinfo.elc create mode 100644 xemacs-packages/lisp/texinfo/texnfo-tex.el create mode 100644 xemacs-packages/lisp/texinfo/texnfo-tex.elc create mode 100644 xemacs-packages/lisp/texinfo/texnfo-upd.el create mode 100644 xemacs-packages/lisp/texinfo/texnfo-upd.elc create mode 100644 xemacs-packages/lisp/text-modes/ChangeLog create mode 100644 xemacs-packages/lisp/text-modes/_pkg.el create mode 100644 xemacs-packages/lisp/text-modes/ansi-color.el create mode 100644 xemacs-packages/lisp/text-modes/ansi-color.elc create mode 100644 xemacs-packages/lisp/text-modes/apache-mode.el create mode 100644 xemacs-packages/lisp/text-modes/apache-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/auto-autoloads.el create mode 100644 xemacs-packages/lisp/text-modes/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/text-modes/autoinsert.el create mode 100644 xemacs-packages/lisp/text-modes/autoinsert.elc create mode 100644 xemacs-packages/lisp/text-modes/crontab.el create mode 100644 xemacs-packages/lisp/text-modes/crontab.elc create mode 100644 xemacs-packages/lisp/text-modes/css-mode.el create mode 100644 xemacs-packages/lisp/text-modes/css-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/custom-load.el create mode 100644 xemacs-packages/lisp/text-modes/custom-load.elc create mode 100644 xemacs-packages/lisp/text-modes/desktop-entry-mode.el create mode 100644 xemacs-packages/lisp/text-modes/desktop-entry-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/filladapt.el create mode 100644 xemacs-packages/lisp/text-modes/filladapt.elc create mode 100644 xemacs-packages/lisp/text-modes/flyspell.el create mode 100644 xemacs-packages/lisp/text-modes/flyspell.elc create mode 100644 xemacs-packages/lisp/text-modes/folding.el create mode 100644 xemacs-packages/lisp/text-modes/folding.elc create mode 100644 xemacs-packages/lisp/text-modes/hexl.el create mode 100644 xemacs-packages/lisp/text-modes/hexl.elc create mode 100644 xemacs-packages/lisp/text-modes/htmlize.el create mode 100644 xemacs-packages/lisp/text-modes/htmlize.elc create mode 100644 xemacs-packages/lisp/text-modes/image-mode.el create mode 100644 xemacs-packages/lisp/text-modes/image-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/iso-acc.el create mode 100644 xemacs-packages/lisp/text-modes/iso-acc.elc create mode 100644 xemacs-packages/lisp/text-modes/iso-ascii.el create mode 100644 xemacs-packages/lisp/text-modes/iso-ascii.elc create mode 100644 xemacs-packages/lisp/text-modes/iso-cvt.el create mode 100644 xemacs-packages/lisp/text-modes/iso-cvt.elc create mode 100644 xemacs-packages/lisp/text-modes/iso-insert.el create mode 100644 xemacs-packages/lisp/text-modes/iso-insert.elc create mode 100644 xemacs-packages/lisp/text-modes/iso-swed.el create mode 100644 xemacs-packages/lisp/text-modes/iso-swed.elc create mode 100644 xemacs-packages/lisp/text-modes/nroff-mode.el create mode 100644 xemacs-packages/lisp/text-modes/nroff-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/po-compat.el create mode 100644 xemacs-packages/lisp/text-modes/po-compat.elc create mode 100644 xemacs-packages/lisp/text-modes/po-mode.el create mode 100644 xemacs-packages/lisp/text-modes/po-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/rtf-support.el create mode 100644 xemacs-packages/lisp/text-modes/rtf-support.elc create mode 100644 xemacs-packages/lisp/text-modes/scribe.el create mode 100644 xemacs-packages/lisp/text-modes/scribe.elc create mode 100644 xemacs-packages/lisp/text-modes/swedish.el create mode 100644 xemacs-packages/lisp/text-modes/swedish.elc create mode 100644 xemacs-packages/lisp/text-modes/tabify.el create mode 100644 xemacs-packages/lisp/text-modes/tabify.elc create mode 100644 xemacs-packages/lisp/text-modes/tpum.el create mode 100644 xemacs-packages/lisp/text-modes/tpum.elc create mode 100644 xemacs-packages/lisp/text-modes/underline.el create mode 100644 xemacs-packages/lisp/text-modes/underline.elc create mode 100644 xemacs-packages/lisp/text-modes/whitespace-mode.el create mode 100644 xemacs-packages/lisp/text-modes/whitespace-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/whitespace-visual-mode.el create mode 100644 xemacs-packages/lisp/text-modes/whitespace-visual-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/whitespace.el create mode 100644 xemacs-packages/lisp/text-modes/whitespace.elc create mode 100644 xemacs-packages/lisp/text-modes/winmgr-mode.el create mode 100644 xemacs-packages/lisp/text-modes/winmgr-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/ws-mode.el create mode 100644 xemacs-packages/lisp/text-modes/ws-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/xpm-mode.el create mode 100644 xemacs-packages/lisp/text-modes/xpm-mode.elc create mode 100644 xemacs-packages/lisp/text-modes/xrdb-mode.el create mode 100644 xemacs-packages/lisp/text-modes/xrdb-mode.elc create mode 100644 xemacs-packages/lisp/tramp/ChangeLog create mode 100644 xemacs-packages/lisp/tramp/ChangeLog.upstream create mode 100644 xemacs-packages/lisp/tramp/_pkg.el create mode 100644 xemacs-packages/lisp/tramp/auto-autoloads.el create mode 100644 xemacs-packages/lisp/tramp/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/tramp/custom-load.el create mode 100644 xemacs-packages/lisp/tramp/custom-load.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-efs.el create mode 100644 xemacs-packages/lisp/tramp/tramp-efs.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-ftp.el create mode 100644 xemacs-packages/lisp/tramp/tramp-ftp.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-smb.el create mode 100644 xemacs-packages/lisp/tramp/tramp-smb.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-util.el create mode 100644 xemacs-packages/lisp/tramp/tramp-util.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-uu.el create mode 100644 xemacs-packages/lisp/tramp/tramp-uu.elc create mode 100644 xemacs-packages/lisp/tramp/tramp-vc.el create mode 100644 xemacs-packages/lisp/tramp/tramp-vc.elc create mode 100644 xemacs-packages/lisp/tramp/tramp.el create mode 100644 xemacs-packages/lisp/tramp/tramp.elc create mode 100644 xemacs-packages/lisp/tramp/trampcache.el create mode 100644 xemacs-packages/lisp/tramp/trampcache.elc create mode 100644 xemacs-packages/lisp/tramp/trampver.el create mode 100644 xemacs-packages/lisp/tramp/trampver.elc create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/ChangeLog create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/INSTALL create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/INSTALL.ja create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/LAST-VERSION create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/Makefile create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/NEWS create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/NEWS.ja create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/README.ja create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/README.markdown create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/TODO create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/VERSION create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/cert/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/cert/Equifax_Secure_Certificate_Authority.cer create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/cert/GeoTrust_Global_CA.cer create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/cert/PCA-3G2.pem create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/Makefile create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/manual/Makefile create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/manual/fdl.texi create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/manual/twmode.texinfo create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/.htaccess create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/Makefile create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/footer.rhtml create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/header.rhtml create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/how-to-contribute.text create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/bottom.jpg create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/content.jpg create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/famfamfam-logo.png create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/lang-en.png create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/lang-ja.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/logo.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/logo.svg create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/menu.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/pic.jpg create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/screen-friends-no-icon.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/screen-friends.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/screen-user-no-icon.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/screen-user.png create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/images/top.jpg create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/index.text create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/ja.po create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/publish.rb create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/screenshot.text create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/doc/web/style.css create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/emacs21/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/emacs21/hex-util.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/emacs21/sha1.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/emacs21/tls.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/howto/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/howto/release create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/http-client.rb create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/misc/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/misc/twitter-icon.svg create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/misc/vernum-updater.rb create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/test.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/test/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/test/el-test-runner.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/test/fixture/timeline-data.el create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/test/run-test.sh create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/test/server.rb create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/test/test-twittering-mode.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/twittering-mode.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/auto-autoloads.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/custom-load.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/docomp.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-about.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-auth.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-auto.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-buffer.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-cache.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-cid.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-cookie.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-dav.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-dired.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-expand.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-file.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-ftp.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-gw.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-handlers.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-history.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-http.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-https.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-imap.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-irc.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-ldap.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-mailto.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-methods.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-misc.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-news.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-nfs.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-ns.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-parse.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-privacy.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-proxy.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-util.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url-vars.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/url.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/url-emacs21/vc-dav.el create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/.nosearch create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/README_j.txt create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/curl-ca-bundle.crt create mode 100755 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/curl.exe create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/CHANGES create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/COPYING create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/FAQ create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/FEATURES create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/LICENSE.OpenSSL.txt create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/README create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/README.win32 create mode 100644 xemacs-packages/lisp/twittering-mode-3.0.0/win-curl/docs/curl.html create mode 100644 xemacs-packages/lisp/xemacs-base/ChangeLog create mode 100644 xemacs-packages/lisp/xemacs-base/_pkg.el create mode 100644 xemacs-packages/lisp/xemacs-base/add-log.el create mode 100644 xemacs-packages/lisp/xemacs-base/add-log.elc create mode 100644 xemacs-packages/lisp/xemacs-base/advice.el create mode 100644 xemacs-packages/lisp/xemacs-base/advice.elc create mode 100644 xemacs-packages/lisp/xemacs-base/annotations.el create mode 100644 xemacs-packages/lisp/xemacs-base/annotations.elc create mode 100644 xemacs-packages/lisp/xemacs-base/assoc.el create mode 100644 xemacs-packages/lisp/xemacs-base/assoc.elc create mode 100644 xemacs-packages/lisp/xemacs-base/auto-autoloads.el create mode 100644 xemacs-packages/lisp/xemacs-base/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/xemacs-base/case-table.el create mode 100644 xemacs-packages/lisp/xemacs-base/case-table.elc create mode 100644 xemacs-packages/lisp/xemacs-base/chistory.el create mode 100644 xemacs-packages/lisp/xemacs-base/chistory.elc create mode 100644 xemacs-packages/lisp/xemacs-base/comint-xemacs.el create mode 100644 xemacs-packages/lisp/xemacs-base/comint-xemacs.elc create mode 100644 xemacs-packages/lisp/xemacs-base/comint.el create mode 100644 xemacs-packages/lisp/xemacs-base/comint.elc create mode 100644 xemacs-packages/lisp/xemacs-base/compile.el create mode 100644 xemacs-packages/lisp/xemacs-base/compile.elc create mode 100644 xemacs-packages/lisp/xemacs-base/custom-load.el create mode 100644 xemacs-packages/lisp/xemacs-base/custom-load.elc create mode 100644 xemacs-packages/lisp/xemacs-base/debug.el create mode 100644 xemacs-packages/lisp/xemacs-base/debug.elc create mode 100644 xemacs-packages/lisp/xemacs-base/easy-mmode.el create mode 100644 xemacs-packages/lisp/xemacs-base/easy-mmode.elc create mode 100644 xemacs-packages/lisp/xemacs-base/ebuff-menu.el create mode 100644 xemacs-packages/lisp/xemacs-base/ebuff-menu.elc create mode 100644 xemacs-packages/lisp/xemacs-base/echistory.el create mode 100644 xemacs-packages/lisp/xemacs-base/echistory.elc create mode 100644 xemacs-packages/lisp/xemacs-base/edmacro.el create mode 100644 xemacs-packages/lisp/xemacs-base/edmacro.elc create mode 100644 xemacs-packages/lisp/xemacs-base/ehelp.el create mode 100644 xemacs-packages/lisp/xemacs-base/ehelp.elc create mode 100644 xemacs-packages/lisp/xemacs-base/electric.el create mode 100644 xemacs-packages/lisp/xemacs-base/electric.elc create mode 100644 xemacs-packages/lisp/xemacs-base/enriched.el create mode 100644 xemacs-packages/lisp/xemacs-base/enriched.elc create mode 100644 xemacs-packages/lisp/xemacs-base/env.el create mode 100644 xemacs-packages/lisp/xemacs-base/env.elc create mode 100644 xemacs-packages/lisp/xemacs-base/facemenu.el create mode 100644 xemacs-packages/lisp/xemacs-base/facemenu.elc create mode 100644 xemacs-packages/lisp/xemacs-base/ffap.el create mode 100644 xemacs-packages/lisp/xemacs-base/ffap.elc create mode 100644 xemacs-packages/lisp/xemacs-base/field.el create mode 100644 xemacs-packages/lisp/xemacs-base/field.elc create mode 100644 xemacs-packages/lisp/xemacs-base/helper.el create mode 100644 xemacs-packages/lisp/xemacs-base/helper.elc create mode 100644 xemacs-packages/lisp/xemacs-base/imenu.el create mode 100644 xemacs-packages/lisp/xemacs-base/imenu.elc create mode 100644 xemacs-packages/lisp/xemacs-base/iso-syntax.el create mode 100644 xemacs-packages/lisp/xemacs-base/iso-syntax.elc create mode 100644 xemacs-packages/lisp/xemacs-base/macros.el create mode 100644 xemacs-packages/lisp/xemacs-base/macros.elc create mode 100644 xemacs-packages/lisp/xemacs-base/novice.el create mode 100644 xemacs-packages/lisp/xemacs-base/novice.elc create mode 100644 xemacs-packages/lisp/xemacs-base/outline.el create mode 100644 xemacs-packages/lisp/xemacs-base/outline.elc create mode 100644 xemacs-packages/lisp/xemacs-base/passwd.el create mode 100644 xemacs-packages/lisp/xemacs-base/passwd.elc create mode 100644 xemacs-packages/lisp/xemacs-base/pp.el create mode 100644 xemacs-packages/lisp/xemacs-base/pp.elc create mode 100644 xemacs-packages/lisp/xemacs-base/regexp-opt.el create mode 100644 xemacs-packages/lisp/xemacs-base/regexp-opt.elc create mode 100644 xemacs-packages/lisp/xemacs-base/regi.el create mode 100644 xemacs-packages/lisp/xemacs-base/regi.elc create mode 100644 xemacs-packages/lisp/xemacs-base/ring.el create mode 100644 xemacs-packages/lisp/xemacs-base/ring.elc create mode 100644 xemacs-packages/lisp/xemacs-base/shell.el create mode 100644 xemacs-packages/lisp/xemacs-base/shell.elc create mode 100644 xemacs-packages/lisp/xemacs-base/skeleton.el create mode 100644 xemacs-packages/lisp/xemacs-base/skeleton.elc create mode 100644 xemacs-packages/lisp/xemacs-base/sort.el create mode 100644 xemacs-packages/lisp/xemacs-base/sort.elc create mode 100644 xemacs-packages/lisp/xemacs-base/thing.el create mode 100644 xemacs-packages/lisp/xemacs-base/thing.elc create mode 100644 xemacs-packages/lisp/xemacs-base/time-stamp.el create mode 100644 xemacs-packages/lisp/xemacs-base/time-stamp.elc create mode 100644 xemacs-packages/lisp/xemacs-base/timer-funcs.el create mode 100644 xemacs-packages/lisp/xemacs-base/timer-funcs.elc create mode 100644 xemacs-packages/lisp/xemacs-base/timezone.el create mode 100644 xemacs-packages/lisp/xemacs-base/timezone.elc create mode 100644 xemacs-packages/lisp/xemacs-base/tq.el create mode 100644 xemacs-packages/lisp/xemacs-base/tq.elc create mode 100644 xemacs-packages/lisp/xemacs-base/xbm-button.el create mode 100644 xemacs-packages/lisp/xemacs-base/xbm-button.elc create mode 100644 xemacs-packages/lisp/xemacs-base/xpm-button.el create mode 100644 xemacs-packages/lisp/xemacs-base/xpm-button.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/ChangeLog create mode 100644 xemacs-packages/lisp/xemacs-devel/_pkg.el create mode 100644 xemacs-packages/lisp/xemacs-devel/auto-autoloads.el create mode 100644 xemacs-packages/lisp/xemacs-devel/auto-autoloads.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/bench.el create mode 100644 xemacs-packages/lisp/xemacs-devel/bench.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/checkdoc.el create mode 100644 xemacs-packages/lisp/xemacs-devel/checkdoc.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/custom-load.el create mode 100644 xemacs-packages/lisp/xemacs-devel/custom-load.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/docref.el create mode 100644 xemacs-packages/lisp/xemacs-devel/docref.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/eldoc.el create mode 100644 xemacs-packages/lisp/xemacs-devel/eldoc.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/elp.el create mode 100644 xemacs-packages/lisp/xemacs-devel/elp.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/eval-expr.el create mode 100644 xemacs-packages/lisp/xemacs-devel/eval-expr.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/find-func.el create mode 100644 xemacs-packages/lisp/xemacs-devel/find-func.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/find-gc.el create mode 100644 xemacs-packages/lisp/xemacs-devel/find-gc.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/hide-copyleft.el create mode 100644 xemacs-packages/lisp/xemacs-devel/hide-copyleft.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/ielm.el create mode 100644 xemacs-packages/lisp/xemacs-devel/ielm.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/lisp-file-db.el create mode 100644 xemacs-packages/lisp/xemacs-devel/lisp-file-db.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/patch-keywords.el create mode 100644 xemacs-packages/lisp/xemacs-devel/patch-keywords.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/patcher.el create mode 100644 xemacs-packages/lisp/xemacs-devel/patcher.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/pretty-print.el create mode 100644 xemacs-packages/lisp/xemacs-devel/pretty-print.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/profile.el create mode 100644 xemacs-packages/lisp/xemacs-devel/profile.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/reposition.el create mode 100644 xemacs-packages/lisp/xemacs-devel/reposition.elc create mode 100644 xemacs-packages/lisp/xemacs-devel/trace.el create mode 100644 xemacs-packages/lisp/xemacs-devel/trace.elc create mode 100644 xemacs-packages/man/bbdb/bbdb.texinfo create mode 100644 xemacs-packages/man/ediff/ediff.texi create mode 100644 xemacs-packages/man/edit-utils/edit-utils.texi create mode 100644 xemacs-packages/man/edit-utils/tempo.texi create mode 100644 xemacs-packages/man/mail-lib/smtpmail.texi create mode 100644 xemacs-packages/man/os-utils/os-utils.texi create mode 100644 xemacs-packages/man/pgg/pgg.texi create mode 100644 xemacs-packages/man/prog-modes/prog-modes.texi create mode 100644 xemacs-packages/man/re-builder/re-builder.texi create mode 100644 xemacs-packages/man/speedbar/speedbar.texi create mode 100644 xemacs-packages/man/tramp/tramp.texi create mode 100644 xemacs-packages/man/tramp/tramp_ja.texi create mode 100644 xemacs-packages/man/xemacs-devel/patcher.texi create mode 100644 xemacs-packages/pkginfo/MANIFEST.bbdb create mode 100644 xemacs-packages/pkginfo/MANIFEST.c-support create mode 100644 xemacs-packages/pkginfo/MANIFEST.ecrypto create mode 100644 xemacs-packages/pkginfo/MANIFEST.ediff create mode 100644 xemacs-packages/pkginfo/MANIFEST.edit-utils create mode 100644 xemacs-packages/pkginfo/MANIFEST.mail-lib create mode 100644 xemacs-packages/pkginfo/MANIFEST.net-utils create mode 100644 xemacs-packages/pkginfo/MANIFEST.os-utils create mode 100644 xemacs-packages/pkginfo/MANIFEST.perl-modes create mode 100644 xemacs-packages/pkginfo/MANIFEST.pgg create mode 100644 xemacs-packages/pkginfo/MANIFEST.prog-modes create mode 100644 xemacs-packages/pkginfo/MANIFEST.python-modes create mode 100644 xemacs-packages/pkginfo/MANIFEST.re-builder create mode 100644 xemacs-packages/pkginfo/MANIFEST.sh-script create mode 100644 xemacs-packages/pkginfo/MANIFEST.speedbar create mode 100644 xemacs-packages/pkginfo/MANIFEST.texinfo create mode 100644 xemacs-packages/pkginfo/MANIFEST.text-modes create mode 100644 xemacs-packages/pkginfo/MANIFEST.tramp create mode 100644 xemacs-packages/pkginfo/MANIFEST.xemacs-base create mode 100644 xemacs-packages/pkginfo/MANIFEST.xemacs-devel diff --git a/ac-dict/cfengine3-mode b/ac-dict/cfengine3-mode new file mode 100644 index 00000000..142f5c41 --- /dev/null +++ b/ac-dict/cfengine3-mode @@ -0,0 +1,36 @@ +bundle agent +classes: +commands: +files: +methods: +reports: +services: +vars: +handle => +comment => +copy_from => local_cp("") +copy_from => local_dcp("") +edit_defaults => +edit_line => +perms => mog("644","root","root"), +create => "true", +create => "false", +classes => +classes => if_repaired("") +delete => tidy +ifvarclass => +getindices(); +getvalues(); +link_from => ln_s("") +move_obstructions => "true" +edit_line => append_if_no_lines( "${lines}" ) +edit_line => expand_variables( "" ) +edit_line => comment_lines_containing("") +usebundle => +string => " +slist => { +package_policy => "add" +package_method => yum_rpm +package_method => yum_rpm_ggs +service_policy => +service_method => service_test \ No newline at end of file diff --git a/centered-cursor-mode.el b/centered-cursor-mode.el new file mode 100644 index 00000000..35565b8f --- /dev/null +++ b/centered-cursor-mode.el @@ -0,0 +1,421 @@ +;;; centered-cursor-mode.el --- cursor stays vertically centered + +;; Copyright (C) 2007 André Riemann + +;; Author: André Riemann +;; Maintainer: André Riemann +;; Created: 2007-09-14 +;; Keywords: convenience + +;; URL: http://www.emacswiki.org/cgi-bin/wiki/centered-cursor-mode.el +;; Compatibility: only tested with GNU Emacs 23.0 +;; Version: 0.5.2 +;; Last-Updated: 2009-08-31 + +;; 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: + +;; Makes the cursor stay vertically in a defined position (usually +;; centered). The vertical position can be altered, see key definition +;; below. + +;; To load put that in .emacs: +;; (require 'centered-cursor-mode) +;; To activate do: +;; M-x centered-cursor-mode +;; for buffer local or +;; M-x global-centered-cursor-mode +;; for global minor mode. +;; Also possible: put that in .emacs +;; (and +;; (require 'centered-cursor-mode) +;; (global-centered-cursor-mode +1)) +;; to always have centered-cursor-mode on in all buffers. + +;;; TODO: +;; - the code is a mess +;; - ccm-vpos-inverted doesn't work with ccm-vpos == 0, because first +;; position from top is 0 and from bottom -1 +;; - interactive first start isn't animated when calling global-... +;; because it starts the modes for each buffer and interactive-p fails +;; for that +;; - more bugs? + +;;; Change Log: +;; 2009-08-31 andre-r +;; * replaced window-body-height with window-text-height +;; (partially visible lines are not counted in window-text-height) +;; * bug fixed in ccm-vpos-recenter +;; (some parentheses where wrong after the last update) +;; 2009-02-23 andre-r +;; * some simplifications +;; 2009-02-22 andre-r +;; * some tips from Drew Adams: +;; - new local variable coding:utf-8 +;; - made recenter-sequence a defvar +;; - added groups scrolling and convenience +;; - replaced mouse-4 and mouse-5 with +;; mouse-wheel-up-event and mouse-wheel-down-event +;; - added scroll-bar-toolkit-scroll to ccm-ignored-commands +;; - made ccm-ignored-commands customisable +;; * removed a bug where it didn't work with more than one window +;; displaying the same buffer +;; * added function for page up and down scrolling +;; (standard ones didn't work well with this mode) +;; * made the animation delay customisable +;; * made the initial vertical position customisable +;; * made the behaviour at the end of the file customisable +;; 2008-02-02 andre-r +;; * fixed bug that led to wrong-type-argument +;; when opening a new buffer +;; * some other minor stuff +;; 2007-09-24 andre-r +;; * added global minor mode +;; 2007-09-21 andre-r +;; * not recentering at end of buffer +;; * defvar animate-first-start-p +;; 2007-09-14 andre-r +;; * inital release + +;; This file is *NOT* part of GNU Emacs. + +;;; Code: + +(defgroup centered-cursor nil + "Makes the cursor stay vertically in a defined position (usually centered). +Instead the cursor the text moves around the cursor." + :group 'scrolling + :group 'convenience + :link '(emacs-library-link :tag "Source Lisp File" "centered-cursor-mode.el") + :link '(url-link "http://www.emacswiki.org/cgi-bin/wiki/centered-cursor-mode.el")) + +(defcustom ccm-step-size 2 + "Step size when animated recentering." + :group 'centered-cursor + :tag "Animation step size" + :type 'integer) + +(defcustom ccm-step-delay 0.02 + "Delay between animation steps. +If you want a different animation speed." + :group 'centered-cursor + :tag "Animation step delay" + :type 'number) + +(defcustom ccm-ignored-commands '(mouse-drag-region + mouse-set-point + widget-button-click + scroll-bar-toolkit-scroll) + "After these commands recentering is ignored. +This is to prevent unintentional jumping (especially when mouse +clicking). Following commands (except the ignored ones) will +cause an animated recentering to give a feedback and not just +jumping to the center." + :group 'centered-cursor + :tag "Ignored commands" + :type '(repeat (symbol :tag "Command"))) + +(defcustom ccm-vpos-init '(round (window-text-height) 2) + "This is the screen line position where the cursor initially stays." + :group 'centered-cursor + :tag "Vertical cursor position" + :type '(choice (const :tag "Center" (round (window-text-height) 2)) + (const :tag "Golden ratio" (round (* 21 (window-text-height)) 34)) + (integer :tag "Lines from top" :value 10))) +(make-variable-buffer-local 'ccm-vpos-init) + +(defcustom ccm-vpos-inverted 1 + "Inverted vertical cursor position. +Defines if the initial vertical position `ccm-vpos-init' is +measured from the bottom instead from the top." + :group 'centered-cursor + :tag "Inverted cursor position" + :type '(choice (const :tag "Inverted" -1) + (const :tag "Not inverted" 1))) +(make-variable-buffer-local 'ccm-vpos-inverted) + +(defcustom ccm-recenter-at-end-of-file nil + "Recenter at the end of the file. +If non-nil the end of the file is recentered. If nil the end of +the file stays at the end of the window." + :group 'centered-cursor + :tag "Recenter at EOF" + :type '(choice (const :tag "Don't recenter at the end of the file" nil) + (const :tag "Recenter at the end of the file" t))) +(make-variable-buffer-local 'ccm-recenter-end-of-file) + +(defvar ccm-vpos nil + "This is the screen line position where the cursor stays.") +(make-variable-buffer-local 'ccm-vpos) + +(defvar animate-first-start-p nil + "Whether or not to animate at first start. It is set to nil, if +centered-cursor-mode is called non-interactively.") +(make-variable-buffer-local 'animate-first-start-p) + +(defvar recenter-sequence nil + "Before animated recentering a list is generated first with positions +to successively recenter to") +(make-variable-buffer-local 'recenter-sequence) + +(defvar ccm-map + (let ((ccm-map (make-sparse-keymap))) + (define-key ccm-map [(control meta -)] 'ccm-vpos-up) + (define-key ccm-map [(control meta +)] 'ccm-vpos-down) + (define-key ccm-map [(control meta =)] 'ccm-vpos-down) + (define-key ccm-map [(control meta ?0)] 'ccm-vpos-recenter) + (when mouse-wheel-mode + (mapc (lambda (key) + (define-key ccm-map key 'ccm-mwheel-scroll)) + (list (vector mouse-wheel-up-event) + (vector mouse-wheel-down-event) + (vector (list 'control mouse-wheel-up-event)) + (vector (list 'control mouse-wheel-down-event)) + (vector (list 'shift mouse-wheel-up-event)) + (vector (list 'shift mouse-wheel-down-event))))) + (define-key ccm-map [(meta v)] 'ccm-scroll-down) + (define-key ccm-map [(control v)] 'ccm-scroll-up) + (define-key ccm-map [prior] 'ccm-scroll-down) + (define-key ccm-map [next] 'ccm-scroll-up) + ccm-map) + "Keymap used in centered-cursor-mode.") + + +(defun ccm-mwheel-scroll (event) + "Very similar to `mwheel-scroll', but does not use `scroll-down' +and `scroll-up' but `previous-line' and `next-line', that is, the +cursor is moved and thus the text in the window is scrolled +due to `recenter'. + +The customizable variable `mouse-wheel-scroll-amount' is used to +determine how much to scroll, where nil instead of a number means +the same as in mwheel-scroll, scroll by a near full screen. + +This command exists, because mwheel-scroll caused strange +behaviour with automatic recentering." +;; (interactive (list last-input-event)) + (interactive "e") + (let* ((mods (delq 'click (delq 'double (delq 'triple (event-modifiers event))))) + (amt (assoc mods mouse-wheel-scroll-amount))) + ;;(message "%S" mods) + (if amt + (setq amt (or (cdr amt) + (- (window-text-height) + next-screen-context-lines))) + (let ((list-elt mouse-wheel-scroll-amount)) + (while (consp (setq amt (pop list-elt)))))) + (if mouse-wheel-follow-mouse + (select-window (posn-window (event-start event)))) + (let ((button (mwheel-event-button event))) + (cond + ((eq button mouse-wheel-down-event) + (forward-line (- amt))) + ;;(princ amt)) + ((eq button mouse-wheel-up-event) + (forward-line amt)) + ;;(princ amt)) + (t (error "Bad binding in ccm-mwheel-scroll")))))) + +(defun ccm-scroll-down (&optional arg) + "Replaces `scroll-down' because with scroll-down +`centered-cursor-mode' sometimes doesn't reach the top of the +buffer. This version actually moves the cursor with +`previous-line'. Since with centered-cursor-mode the cursor is in +a fixed position the movement appears as page up." + (interactive "P") + (let ((amt (or arg (- (window-text-height) + next-screen-context-lines)))) + (forward-line (- amt)))) + +(defun ccm-scroll-up (&optional arg) + "Replaces `scroll-up' to be consistent with `ccm-scroll-down'. +This version actually moves the cursor with `previous-line'. +Since with centered-cursor-mode the cursor is in a fixed position +the movement appears as page up." + (interactive "P") + (let ((amt (or arg (- (window-text-height) + next-screen-context-lines)))) + (forward-line amt))) + + +(defun ccm-vpos-down (arg) + "Adjust the value of the screen line (where the cursor stays) by arg. +Negative values for arg are possible. Just the variable ccm-vpos +is set." + (interactive "p") + (or arg (setq arg 1)) + (let ((new-pos (if (< ccm-vpos 0) + (- ccm-vpos arg) + (+ ccm-vpos arg))) + ;; see pos-visible-in-window-p + (vpos-max (if (< ccm-vpos 0) + -1 + (- (window-text-height) 1))) + (vpos-min (if (< ccm-vpos 0) + (- (window-text-height)) + 0))) + (setq ccm-vpos + (cond + ((< new-pos vpos-min) + vpos-min) + ((> new-pos vpos-max) + vpos-max) + (t + new-pos))))) + +(defun ccm-vpos-up (arg) + "See `ccm-vpos-down'." + (interactive "p") + (or arg (setq arg 1)) + (ccm-vpos-down (- arg))) + +(defun ccm-vpos-recenter () + "Set the value of the screen line (where the cursor stays) in +the center. Just the variable ccm-vpos is set." + (interactive) + (if (equal (current-buffer) + (window-buffer (selected-window))) + (setq ccm-vpos (* (eval ccm-vpos-init) + ccm-vpos-inverted)))) + +(defun ccm-position-cursor () + "Do the actual recentering at the position `ccm-vpos'." + (unless (member this-command ccm-ignored-commands) + (unless ccm-vpos + (ccm-vpos-recenter)) + (unless (minibufferp (current-buffer)) + (if (equal (current-buffer) + (window-buffer (selected-window))) + (let* ((current-line + (if (< ccm-vpos 0) + ;; one-based, from bottom, negative + (- (count-lines (point) + ;; window-end is sometimes < 0 + ;; when opening a help buffer + (if (> (window-end) 0) + (window-end) + 1))) + ;; zero-based, from top, positive + (+ (count-lines (window-start) (point)) + ;; count-lines returns different value in column 0 + (if (= (current-column) 0) 0 -1)))) + (diff (- ccm-vpos current-line)) + (step-size ccm-step-size) + (step-delay ccm-step-delay) + (vpos-inverted ccm-vpos-inverted) + (recenter-at-end-of-file ccm-recenter-at-end-of-file)) + + (let* ((bottom-vpos (if (< ccm-vpos 0) + (- ccm-vpos) + (- (window-text-height) ccm-vpos))) + (correction (save-excursion + (if (or (= (point) (point-max)) + (progn + (goto-char (point-max)) + (zerop (current-column)))) + 1 0))) + ;; lines from point to end of buffer + (bottom-lines (+ (count-lines (point) (point-max)) + correction))) + + ;; only animate if the point was moved rather far away + ;; before by a mouseclick (see ccm-ignored-commands) + ;; or if minor mode is just entered interactively + (if (not (and (> (abs diff) 4) + (or (member last-command ccm-ignored-commands) + animate-first-start-p))) + + (recenter (if (and (< bottom-lines bottom-vpos) + (not recenter-at-end-of-file)) + ;; if near the bottom, recenter in the + ;; negative screen line that equals the + ;; bottom buffer line, i.e. if we are in + ;; the second last line (-2) of the + ;; buffer, the cursor will be recentered + ;; in -2 + (- bottom-lines) + ccm-vpos)) + + (setq animate-first-start-p nil) + ;; first build a list with positions to successively recenter to + (setq recenter-sequence + ;; reverse: because we build the list not FROM -> TO but + ;; TO -> FROM because if step size in number-sequence is + ;; bigger than one, TO might not included, that means the + ;; ccm-vpos would not be reached + ;; cdr: don't recenter the current-line + (if (and (< bottom-lines bottom-vpos) + (not recenter-at-end-of-file)) + ;; this one is for animation near the bottom + (cdr (reverse (number-sequence + (- bottom-lines) + (if (< ccm-vpos 0) + current-line + (- (- (window-text-height) current-line))) + (* (/ diff (abs diff)) (- step-size))))) + (cdr (reverse (number-sequence + ccm-vpos + current-line + (* (/ diff (abs diff)) (- step-size))))))) + ;; (message "%d %d %d (%d): %S" current-line ccm-vpos bottom-lines diff recenter-sequence) + (while recenter-sequence + ;; actual animation + (recenter (pop recenter-sequence)) + (if (car recenter-sequence) (sit-for step-delay t)))))))))) + +(defun ccm-first-start (animate) + "Called from centered-cursor-mode. Animate at first start, if +centered-cursor-mode is called interactively." + (let ((animate-first-start-p animate)) + (ccm-vpos-recenter) + (ccm-position-cursor))) + +;;(defalias 'ccm 'centered-cursor-mode) +(define-minor-mode centered-cursor-mode + "Makes the cursor stay vertically in a defined +position (usually centered)." + :init-value nil +;; :lighter nil + :lighter " ¢" + :keymap ccm-map + (cond + (centered-cursor-mode + (ccm-first-start (interactive-p)) + (add-hook 'post-command-hook 'ccm-position-cursor t t) + (add-hook 'window-configuration-change-hook 'ccm-vpos-recenter t t)) + (t + (remove-hook 'post-command-hook 'ccm-position-cursor t) + (remove-hook 'window-configuration-change-hook 'ccm-vpos-recenter t)))) + + +(define-global-minor-mode global-centered-cursor-mode centered-cursor-mode + centered-cursor-mode) + +(provide 'centered-cursor-mode) + +;;; Help: +;; (info "(elisp)Defining Minor Modes") +;; (info "(elisp)Screen Lines") +;; (info "(elisp)Hooks") +;; (info "(elisp)Customization") +;; (find-function 'mwheel-scroll) + +;; Local Variables: +;; coding: utf-8 +;; End: + +;;; centered-cursor-mode.el ends here diff --git a/centered-cursor-mode.elc b/centered-cursor-mode.elc new file mode 100644 index 0000000000000000000000000000000000000000..7f20c331e0d88bb2ab6e09375e5c3e2563688205 GIT binary patch literal 13519 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 literal 0 HcmV?d00001 diff --git a/cfengine-code-style.el b/cfengine-code-style.el new file mode 100644 index 00000000..d1db90d3 --- /dev/null +++ b/cfengine-code-style.el @@ -0,0 +1,58 @@ +;;; +;;; C code style for CFEngine project. +;;; +;;; Author: Mikhail Gusarov +;;; +;;; +;;; Usage: +;;; +;;; To enable coding style for the current buffer: +;;; +;;; M-x c-set-style cfengine +;;; +;;; To enable coding style permanently, create file .dir-locals.el with the +;;; following contents in the directory with the source code: +;;; +;;; ((c-mode . ((c-file-style . "cfengine")))) +;;; + +;; +;; TODO: special rule for C99 (Foo) { 1, 2, 3 } initializers. +;; TODO: special rule for whitespace between if/while/for and paren. +;; + +(defconst cfengine-c-style + '(;; 4 spaces + (c-basic-offset . 4) + ;; Braces on new lines + (c-hanging-braces-alist . ((substatement-open before after) + (statement-cont) + (brace-list-open) + (brace-list-close) + (brace-list-intro) + (brace-entry-open))) + ;; Newline after 'case' label + (c-hanging-colons-alist . ((case-label after))) + ;; Don't place comma on a separate line after array/aggregate + (c-cleanup-list . (list-close-comma)) + ;; Indentation + (c-offsets-alist . ((defun-open . 0) + (defun-block-intro . +) + (substatement-open . 0) + (statement-cont . +)))) + "CFEngine Code Style") + +(c-add-style "CFEngine" cfengine-c-style) + +;; +;; CFEngine uses CapitalizedWords for function names +;; + +(defun cfengine-c-mode-hook () + (if (eq c-file-style "CFEngine") + (progn + (setq indent-tabs-mode nil) + (setq c-tab-always-indent t) + (subword-mode 1)))) + +(add-hook 'c-mode-hook 'cfengine-c-mode-hook) diff --git a/cfengine-code-style.elc b/cfengine-code-style.elc new file mode 100644 index 0000000000000000000000000000000000000000..43c296b39b51f415e8f3f7f4a048f843576fed22 GIT binary patch literal 1272 zcmbtU-*3|}5bh&H;sIWGp~ir2vdR4 z@RikU76q zn4k)QQo~h)fqS%05=Ayi(j*POjr1$vN`a}ptmJR*3E+|_IDf39YZ=!L9TZ#5D=DBb z!g(w8(!C?Ebsl(8P<;oU^diYFk|>rX#9S8;=Vq;o8U{fs+sPP4Pa%F!2#Y0jJP@Z0 zVnqd!xQ=Hy9Ky#>A=22tlh;P9X0v^E!0w*dnkR0hGlkC8-Q>^@!uv!L1t?leEd8JV z?(G0J+yPCloo-3cw#^|6&{lDemePf8(oy)YCyJtz%PfV(=c_PiI#&h4_h!(qqPW0P z(BM2AwYG-<25~G{&Ycv@l%+!t2~3AT#uaZ8Em>~4K*zX}6d${F?mP*vPOUF`A&H!tPKRjlU}{x!e^ +;; Maintainer: Ted Zlatanov +;; Keywords: languages +;; Version: 1.1 + +;; This file is part of GNU Emacs, but has trivial compatibility +;; modifications for Emacs versions before 24. Emacs 24 and newer +;; includes this code and you should use that version. The following +;; is the copyright notice from Emacs, which still applies to this +;; code and all derivations thereof. + +;; GNU Emacs 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 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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. If not, see . + +;;; Commentary: + +;; Provides support for editing GNU Cfengine files, including +;; font-locking, Imenu and indentation, but with no special keybindings. + +;; The CFEngine 3.x support doesn't have Imenu support but patches are +;; welcome. + +;; You can set it up so either `cfengine2-mode' (2.x and earlier) or +;; `cfengine3-mode' (3.x) will be picked, depending on the buffer +;; contents: + +;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine-mode)) + +;; OR you can choose to always use a specific version, if you prefer +;; it: + +;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine3-mode)) +;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode)) +;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode)) + +;; This is not the same as the mode written by Rolf Ebert +;; , distributed with cfengine-2.0.5. It does +;; better fontification and indentation, inter alia. + +;;; Code: + +;; Set up compatibility with Emacsen where prog-mode doesn't exist. +(defalias 'cfengine-prog-mode (if (fboundp 'prog-mode) + 'prog-mode + 'fundamental-mode)) + +(defgroup cfengine () + "Editing CFEngine files." + :group 'languages) + +(defcustom cfengine-indent 2 + "*Size of a CFEngine indentation step in columns." + :group 'cfengine + :type 'integer) + +(defcustom cfengine-parameters-indent '(promise pname 0) + "*Indentation of CFEngine3 promise parameters (hanging indent). + +For example, say you have this code: + +bundle x y +{ + section: + class:: + promise ... + promiseparameter => ... +} + +You can choose to indent promiseparameter from the beginning of +the line (absolutely) or from the word \"promise\" (relatively). + +You can also choose to indent the start of the word +\"promiseparameter\" or the arrow that follows it. + +Finally, you can choose the amount of the indent. + +The default is to anchor at promise, indent parameter name, and offset 0: + +bundle agent rcfiles +{ + files: + any:: + \"/tmp/netrc\" + comment => \"my netrc\", + perms => mog(\"600\", \"tzz\", \"tzz\"); +} + +Here we anchor at beginning of line, indent arrow, and offset 10: + +bundle agent rcfiles +{ + files: + any:: + \"/tmp/netrc\" + comment => \"my netrc\", + perms => mog(\"600\", \"tzz\", \"tzz\"); +} + +Some, including cfengine_stdlib.cf, like to anchor at promise, indent +arrow, and offset 16 or so: + +bundle agent rcfiles +{ + files: + any:: + \"/tmp/netrc\" + comment => \"my netrc\", + perms => mog(\"600\", \"tzz\", \"tzz\"); +} +" + + :group 'cfengine + :type '(list + (choice (const :tag "Anchor at beginning of promise" promise) + (const :tag "Anchor at beginning of line" bol)) + (choice (const :tag "Indent parameter name" pname) + (const :tag "Indent arrow" arrow)) + (integer :tag "Indentation amount from anchor"))) + +(defvar cfengine-mode-debug nil + "Whether `cfengine-mode' should print debugging info.") + +(defcustom cfengine-mode-abbrevs nil + "Abbrevs for CFEngine2 mode." + :group 'cfengine + :type '(repeat (list (string :tag "Name") + (string :tag "Expansion") + (choice :tag "Hook" (const nil) function)))) + +(make-obsolete-variable 'cfengine-mode-abbrevs 'edit-abbrevs "24.1") + +;; Taken from the doc for pre-release 2.1. +(eval-and-compile + (defconst cfengine2-actions + '("acl" "alerts" "binservers" "broadcast" "control" "classes" "copy" + "defaultroute" "disks" "directories" "disable" "editfiles" "files" + "filters" "groups" "homeservers" "ignore" "import" "interfaces" + "links" "mailserver" "methods" "miscmounts" "mountables" + "processes" "packages" "rename" "required" "resolve" + "shellcommands" "tidy" "unmount" + ;; Keywords for cfservd. + "admit" "grant" "deny") + "List of the action keywords supported by Cfengine. +This includes those for cfservd as well as cfagent.") + + (defconst cfengine3-defuns + (mapcar + 'symbol-name + '(bundle body)) + "List of the CFEngine 3.x defun headings.") + + (defconst cfengine3-defuns-regex + (regexp-opt cfengine3-defuns t) + "Regex to match the CFEngine 3.x defuns.") + + (defconst cfengine3-class-selector-regex "\\([[:alnum:]_().&|!]+\\)::") + + (defconst cfengine3-category-regex "\\([[:alnum:]_]+\\):") + + (defconst cfengine3-vartypes + (mapcar + 'symbol-name + '(string int real slist ilist rlist irange rrange counter)) + "List of the CFEngine 3.x variable types.")) + +(defconst cfengine-font-lock-syntactic-keywords + ;; In the main syntax-table, backslash is marked as a punctuation, because + ;; of its use in DOS-style directory separators. Here we try to recognize + ;; the cases where backslash is used as an escape inside strings. + '(("\\(\\(?:\\\\\\)+\\)\"" 1 "\\"))) + +(defvar cfengine2-font-lock-keywords + `(;; Actions. + ;; List the allowed actions explicitly, so that errors are more obvious. + (,(concat "^[ \t]*" (eval-when-compile + (regexp-opt cfengine2-actions t)) + ":") + 1 font-lock-keyword-face) + ;; Classes. + ("^[ \t]*\\([[:alnum:]_().|!]+\\)::" 1 font-lock-function-name-face) + ;; Variables. + ("$(\\([[:alnum:]_]+\\))" 1 font-lock-variable-name-face) + ("${\\([[:alnum:]_]+\\)}" 1 font-lock-variable-name-face) + ;; Variable definitions. + ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) + ;; File, acl &c in group: { token ... } + ("{[ \t]*\\([^ \t\n]+\\)" 1 font-lock-constant-face))) + +(defvar cfengine3-font-lock-keywords + `( + ;; Defuns. This happens early so they don't get caught by looser + ;; patterns. + (,(concat "\\<" cfengine3-defuns-regex "\\>" + "[ \t]+\\<\\([[:alnum:]_]+\\)\\>" + "[ \t]+\\<\\([[:alnum:]_]+\\)" + ;; Optional parentheses with variable names inside. + "\\(?:(\\([^)]*\\))\\)?") + (1 font-lock-builtin-face) + (2 font-lock-constant-face) + (3 font-lock-function-name-face) + (4 font-lock-variable-name-face nil t)) + + ;; Class selectors. + (,(concat "^[ \t]*" cfengine3-class-selector-regex) + 1 font-lock-keyword-face) + + ;; Categories. + (,(concat "^[ \t]*" cfengine3-category-regex) + 1 font-lock-builtin-face) + + ;; Variables, including scope, e.g. module.var + ("[@$](\\([[:alnum:]_.]+\\))" 1 font-lock-variable-name-face) + ("[@$]{\\([[:alnum:]_.]+\\)}" 1 font-lock-variable-name-face) + + ;; Variable definitions. + ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) + + ;; Variable types. + (,(concat "\\<" (eval-when-compile (regexp-opt cfengine3-vartypes t)) "\\>") + 1 font-lock-type-face))) + +(defvar cfengine2-imenu-expression + `((nil ,(concat "^[ \t]*" (eval-when-compile + (regexp-opt cfengine2-actions t)) + ":[^:]") + 1) + ("Variables/classes" "\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1) + ("Variables/classes" "\\[ \t]+\\([[:alnum:]_]+\\)" 1)) + "`imenu-generic-expression' for CFEngine mode.") + +(defun cfengine2-outline-level () + "`outline-level' function for CFEngine mode." + (if (looking-at "[^:]+\\(?:[:]+\\)$") + (length (match-string 1)))) + +(defun cfengine2-beginning-of-defun () + "`beginning-of-defun' function for CFEngine mode. +Treats actions as defuns." + (unless (<= (current-column) (current-indentation)) + (end-of-line)) + (if (re-search-backward "^[[:alpha:]]+: *$" nil t) + (beginning-of-line) + (goto-char (point-min))) + t) + +(defun cfengine2-end-of-defun () + "`end-of-defun' function for CFEngine mode. +Treats actions as defuns." + (end-of-line) + (if (re-search-forward "^[[:alpha:]]+: *$" nil t) + (beginning-of-line) + (goto-char (point-max))) + t) + +;; Fixme: Should get an extra indent step in editfiles BeginGroup...s. + +(defun cfengine2-indent-line () + "Indent a line in Cfengine mode. +Intended as the value of `indent-line-function'." + (let ((pos (- (point-max) (point)))) + (save-restriction + (narrow-to-defun) + (back-to-indentation) + (cond + ;; Action selectors aren't indented; class selectors are + ;; indented one step. + ((looking-at "[[:alnum:]_().|!]+:\\(:\\)?") + (if (match-string 1) + (indent-line-to cfengine-indent) + (indent-line-to 0))) + ;; Outdent leading close brackets one step. + ((or (eq ?\} (char-after)) + (eq ?\) (char-after))) + (condition-case () + (indent-line-to (save-excursion + (forward-char) + (backward-sexp) + (current-column))) + (error nil))) + ;; Inside brackets/parens: indent to start column of non-comment + ;; token on line following open bracket or by one step from open + ;; bracket's column. + ((condition-case () + (progn (indent-line-to (save-excursion + (backward-up-list) + (forward-char) + (skip-chars-forward " \t") + (if (looking-at "[^\n#]") + (current-column) + (skip-chars-backward " \t") + (+ (current-column) -1 + cfengine-indent)))) + t) + (error nil))) + ;; Indent by two steps after a class selector. + ((save-excursion + (re-search-backward "^[ \t]*[[:alnum:]_().|!]+::" nil t)) + (indent-line-to (* 2 cfengine-indent))) + ;; Indent by one step if we're after an action header. + ((save-excursion + (goto-char (point-min)) + (looking-at "[[:alpha:]]+:[ \t]*$")) + (indent-line-to cfengine-indent)) + ;; Else don't indent. + (t + (indent-line-to 0)))) + ;; If initial point was within line's indentation, + ;; position after the indentation. Else stay at same point in text. + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos))))) + +;; This doesn't work too well in Emacs 21.2. See 22.1 development +;; code. +(defun cfengine-fill-paragraph (&optional justify) + "Fill `paragraphs' in Cfengine code." + (interactive "P") + (or (if (fboundp 'fill-comment-paragraph) + (fill-comment-paragraph justify) ; post Emacs 21.3 + ;; else do nothing in a comment + (nth 4 (parse-partial-sexp (save-excursion + (beginning-of-defun) + (point)) + (point)))) + (let ((paragraph-start + ;; Include start of parenthesized block. + "\f\\|[ \t]*$\\|.*\(") + (paragraph-separate + ;; Include action and class lines, start and end of + ;; bracketed blocks and end of parenthesized blocks to + ;; avoid including these in fill. This isn't ideal. + "[ \t\f]*$\\|.*#\\|.*[\){}]\\|\\s-*[[:alpha:]_().|!]+:") + fill-paragraph-function) + (fill-paragraph justify)) + t)) + +(defun cfengine3-beginning-of-defun () + "`beginning-of-defun' function for Cfengine 3 mode. +Treats body/bundle blocks as defuns." + (unless (<= (current-column) (current-indentation)) + (end-of-line)) + (if (re-search-backward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) + (beginning-of-line) + (goto-char (point-min))) + t) + +(defun cfengine3-end-of-defun () + "`end-of-defun' function for Cfengine 3 mode. +Treats body/bundle blocks as defuns." + (end-of-line) + (if (re-search-forward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) + (beginning-of-line) + (goto-char (point-max))) + t) + +(defun cfengine3-indent-line () + "Indent a line in Cfengine 3 mode. +Intended as the value of `indent-line-function'." + (let ((pos (- (point-max) (point))) + parse) + (save-restriction + (narrow-to-defun) + (back-to-indentation) + (setq parse (parse-partial-sexp (point-min) (point))) + (when cfengine-mode-debug + (message "%S" parse)) + + (cond + ;; Body/bundle blocks start at 0. + ((looking-at (concat cfengine3-defuns-regex "\\>")) + (indent-line-to 0)) + ;; Categories are indented one step. + ((looking-at (concat cfengine3-category-regex "[ \t]*\\(#.*\\)*$")) + (indent-line-to cfengine-indent)) + ;; Class selectors are indented two steps. + ((looking-at (concat cfengine3-class-selector-regex "[ \t]*\\(#.*\\)*$")) + (indent-line-to (* 2 cfengine-indent))) + ;; Outdent leading close brackets one step. + ((or (eq ?\} (char-after)) + (eq ?\) (char-after))) + (condition-case () + (indent-line-to (save-excursion + (forward-char) + (backward-sexp) + (current-column))) + (error nil))) + ;; Inside a string and it starts before this line. + ((and (nth 3 parse) + (< (nth 8 parse) (save-excursion (beginning-of-line) (point)))) + (indent-line-to 0)) + + ;; Inside a defun, but not a nested list (depth is 1). This is + ;; a promise, usually. + ((= 1 (nth 0 parse)) + (let ((p-anchor (nth 0 cfengine-parameters-indent)) + (p-what (nth 1 cfengine-parameters-indent)) + (p-indent (nth 2 cfengine-parameters-indent))) + ;; Do we have the parameter anchor and location and indent + ;; defined, and are we looking at a promise parameter? + (if (and p-anchor p-what p-indent + (looking-at "\\([[:alnum:]_]+[ \t]*\\)=>")) + (let* ((arrow-offset (* -1 (length (match-string 1)))) + (extra-offset (if (eq p-what 'arrow) arrow-offset 0)) + (base-offset (if (eq p-anchor 'promise) + (* (+ 2 (nth 0 parse)) cfengine-indent) + 0))) + (indent-line-to (max 0 (+ p-indent base-offset extra-offset)))) + ;; Else, indent to cfengine-indent times the nested depth + ;; plus 2. That way, promises indent deeper than class + ;; selectors, which in turn are one deeper than categories. + (indent-line-to (* (+ 2 (nth 0 parse)) cfengine-indent))))) + ;; Inside brackets/parens: indent to start column of non-comment + ;; token on line following open bracket or by one step from open + ;; bracket's column. + ((condition-case () + (progn (indent-line-to (save-excursion + (backward-up-list) + (forward-char) + (skip-chars-forward " \t") + (cond + ((looking-at "[^\n#]") + (current-column)) + ((looking-at "[^\n#]") + (current-column)) + (t + (skip-chars-backward " \t") + (+ (current-column) -1 + cfengine-indent))))) + t) + (error nil))) + ;; Else don't indent. + (t (indent-line-to 0)))) + ;; If initial point was within line's indentation, + ;; position after the indentation. Else stay at same point in text. + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos))))) + +;; CFEngine 3.x grammar + +;; specification: blocks +;; blocks: block | blocks block; +;; block: bundle typeid blockid bundlebody +;; | bundle typeid blockid usearglist bundlebody +;; | body typeid blockid bodybody +;; | body typeid blockid usearglist bodybody; + +;; typeid: id +;; blockid: id +;; usearglist: '(' aitems ')'; +;; aitems: aitem | aitem ',' aitems |; +;; aitem: id + +;; bundlebody: '{' statements '}' +;; statements: statement | statements statement; +;; statement: category | classpromises; + +;; bodybody: '{' bodyattribs '}' +;; bodyattribs: bodyattrib | bodyattribs bodyattrib; +;; bodyattrib: class | selections; +;; selections: selection | selections selection; +;; selection: id ASSIGN rval ';' ; + +;; classpromises: classpromise | classpromises classpromise; +;; classpromise: class | promises; +;; promises: promise | promises promise; +;; category: CATEGORY +;; promise: promiser ARROW rval constraints ';' | promiser constraints ';'; +;; constraints: constraint | constraints ',' constraint |; +;; constraint: id ASSIGN rval; +;; class: CLASS +;; id: ID +;; rval: ID | QSTRING | NAKEDVAR | list | usefunction +;; list: '{' litems '}' ; +;; litems: litem | litem ',' litems |; +;; litem: ID | QSTRING | NAKEDVAR | list | usefunction + +;; functionid: ID | NAKEDVAR +;; promiser: QSTRING +;; usefunction: functionid givearglist +;; givearglist: '(' gaitems ')' +;; gaitems: gaitem | gaitems ',' gaitem |; +;; gaitem: ID | QSTRING | NAKEDVAR | list | usefunction + +;; # from lexer: + +;; bundle: "bundle" +;; body: "body" +;; COMMENT #[^\n]* +;; NAKEDVAR [$@][(][a-zA-Z0-9_\200-\377.]+[)]|[$@][{][a-zA-Z0-9_\200-\377.]+[}] +;; ID: [a-zA-Z0-9_\200-\377]+ +;; ASSIGN: "=>" +;; ARROW: "->" +;; QSTRING: \"((\\\")|[^"])*\"|\'((\\\')|[^'])*\'|`[^`]*` +;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+:: +;; CATEGORY: [a-zA-Z_]+: + +(defun cfengine-common-settings () + (if (fboundp 'syntax-propertize-rules) + (set (make-local-variable 'syntax-propertize-function) + ;; In the main syntax-table, \ is marked as a punctuation, because + ;; of its use in DOS-style directory separators. Here we try to + ;; recognize the cases where \ is used as an escape inside strings. + (syntax-propertize-rules ("\\(\\(?:\\\\\\)+\\)\"" (1 "\\")))) + + ;; Backwards compatibility without `syntax-propertize-function'. + (setq font-lock-defaults + '(cfengine2-font-lock-keywords + nil nil nil beginning-of-line + (font-lock-syntactic-keywords + . cfengine-font-lock-syntactic-keywords)))) + + (set (make-local-variable 'parens-require-spaces) nil) + (set (make-local-variable 'comment-start) "# ") + (set (make-local-variable 'comment-start-skip) + "\\(\\(?:^\\|[^\\\\\n]\\)\\(?:\\\\\\\\\\)*\\)#+[ \t]*") + ;; Like Lisp mode. Without this, we lose with, say, + ;; `backward-up-list' when there's an unbalanced quote in a + ;; preceding comment. + (set (make-local-variable 'parse-sexp-ignore-comments) t)) + +(defun cfengine-common-syntax (table) + ;; The syntax defaults seem OK to give reasonable word movement. + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n ">#" table) + (modify-syntax-entry ?\" "\"" table) + ;; Variable substitution. + (modify-syntax-entry ?$ "." table) + ;; Doze path separators. + (modify-syntax-entry ?\\ "." table)) + +;;;###autoload +(define-derived-mode cfengine3-mode cfengine-prog-mode "CFE3" + "Major mode for editing CFEngine3 input. +There are no special keybindings by default. + +Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves +to the action header." + (cfengine-common-settings) + (cfengine-common-syntax cfengine3-mode-syntax-table) + + (set (make-local-variable 'indent-line-function) #'cfengine3-indent-line) + (setq font-lock-defaults + '(cfengine3-font-lock-keywords nil nil nil beginning-of-defun)) + + ;; Use defuns as the essential syntax block. + (set (make-local-variable 'beginning-of-defun-function) + #'cfengine3-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + #'cfengine3-end-of-defun)) + +;;;###autoload +(define-derived-mode cfengine2-mode cfengine-prog-mode "CFE2" + "Major mode for editing CFEngine2 input. +There are no special keybindings by default. + +Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves +to the action header." + (cfengine-common-settings) + (cfengine-common-syntax cfengine2-mode-syntax-table) + + ;; Shell commands can be quoted by single, double or back quotes. + ;; It's debatable whether we should define string syntax, but it + ;; should avoid potential confusion in some cases. + (modify-syntax-entry ?\' "\"" cfengine2-mode-syntax-table) + (modify-syntax-entry ?\` "\"" cfengine2-mode-syntax-table) + + (set (make-local-variable 'indent-line-function) #'cfengine2-indent-line) + (set (make-local-variable 'outline-regexp) "[ \t]*\\(\\sw\\|\\s_\\)+:+") + (set (make-local-variable 'outline-level) #'cfengine2-outline-level) + (set (make-local-variable 'fill-paragraph-function) + #'cfengine-fill-paragraph) + (define-abbrev-table 'cfengine-mode-abbrev-table cfengine2-mode-abbrevs) + (setq font-lock-defaults + '(cfengine2-font-lock-keywords nil nil nil beginning-of-line)) + ;; Fixme: set the args of functions in evaluated classes to string + ;; syntax, and then obey syntax properties. + (setq imenu-generic-expression cfengine2-imenu-expression) + (set (make-local-variable 'beginning-of-defun-function) + #'cfengine2-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) #'cfengine2-end-of-defun)) + +;;;###autoload +(defun cfengine-auto-mode () + "Choose between `cfengine2-mode' and `cfengine3-mode' depending +on the buffer contents" + (let ((v3 nil)) + (save-restriction + (goto-char (point-min)) + (while (not (or (eobp) v3)) + (setq v3 (looking-at (concat cfengine3-defuns-regex "\\>"))) + (forward-line))) + (if v3 (cfengine3-mode) (cfengine2-mode)))) + +(defalias 'cfengine-mode 'cfengine-auto-mode) + +(provide 'cfengine3) +(provide 'cfengine) + +;;; cfengine.el ends here diff --git a/cfengine.elc b/cfengine.elc new file mode 100644 index 0000000000000000000000000000000000000000..a4da8aba307554e744bfc2f24aef6cd0885837c4 GIT binary patch literal 17186 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 Saih}^p$%PCY>AQsYySsK7b$!I literal 0 HcmV?d00001 diff --git a/custom.el b/custom.el new file mode 100644 index 00000000..465e6b5f --- /dev/null +++ b/custom.el @@ -0,0 +1,22 @@ +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(gnuserv-program (concat exec-directory "/gnuserv")) + '(org-agenda-files (quote ("~/org/emacs.org" "~/org/work.org" "~/org/private.org" "~/org/it.org"))) + '(toolbar-visible-p nil) + '(vc-handled-backends (quote (RCS CVS SVN SCCS Bzr Hg Mtn Arch)))) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(default ((t (:size "14pt" :family "Lucidatypewriter")))) + '(toolbar ((t (:background "Gray80" :size "8"))) t)) +(defcustom sql-mysql-program "/usr/local/mysql/bin/mysql" +"*Command to start mysql by mysqlDB." +:type 'file +:group 'SQL) + +(setq minibuffer-max-depth nil) diff --git a/egg-grep.el b/egg-grep.el new file mode 100644 index 00000000..89e73d50 --- /dev/null +++ b/egg-grep.el @@ -0,0 +1,132 @@ +;;; egg -- Emacs Got Git +;;; A magit fork + +;; Copyright (C) 2008 Linh Dang +;; +;; Egg 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 3, or (at your option) +;; any later version. +;; +;; Egg 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. + +;;; Commentary +;;; This is my fork of Marius's excellent magit. his work is at: +;;; http://zagadka.vm.bytemark.co.uk/magit +;;; +(require 'egg) +(require 'compile) +(require 'grep) +(require 'cl) + +(defvar egg-grep-saved-find-file-func nil) + +(defun egg-grep-find-file (marker rev:name dir formats) + (save-match-data + (let* ((rev-name-lst (split-string rev:name ":" t)) + (rev (car rev-name-lst)) + (file (cadr rev-name-lst))) + (unless file + (setq file rev) + (setq rev nil)) + (if rev + (egg-file-get-other-version file rev nil t) + (apply egg-grep-saved-find-file-func marker file dir formats))))) + +(defun egg-grep-next-error-function (n &optional reset) + (interactive "P") + (let ((egg-grep-saved-find-file-func + (symbol-function 'compilation-find-file))) + (flet ((compilation-find-file (marker file-name dir &rest formats) + (egg-grep-find-file marker + file-name + dir formats))) + (compilation-next-error-function n reset)))) + +;;;###autoload +(defun egg-grep-process-setup () + "Setup compilation variables and buffer for `egg-grep'. +Set up `compilation-exit-message-function' and run `egg-grep-setup-hook'." + (set (make-local-variable 'compilation-exit-message-function) + (lambda (status code msg) + (if (eq status 'exit) + (cond ((zerop code) + '("finished (matches found)\n" . "matched")) + ((= code 1) + '("finished with no matches found\n" . "no match")) + (t + (cons msg code))) + (cons msg code)))) + + (run-hooks 'egg-grep-setup-hook)) + + + +(defvar egg-grep-mode-map + (let ((map (make-sparse-keymap "Egg:Grep"))) + (set-keymap-parent map compilation-minor-mode-map) + (define-key map (kbd "SPC") 'scroll-up) + (define-key map (kbd "DEL") 'scroll-down) + + (define-key map (kbd "RET") 'compile-goto-error) + (define-key map "n" 'next-error-no-select) + (define-key map "p" 'previous-error-no-select) + (define-key map "{" 'compilation-previous-file) + (define-key map "}" 'compilation-next-file) + (define-key map (kbd "TAB") 'compilation-next-error) + map) + "Keymap for git-grep buffers. +`compilation-minor-mode-map' is the parent keymap.") + +;;;###autoload +(define-compilation-mode egg-grep-mode "Git-Grep" + "Sets `compilation-last-buffer' and `compilation-window-height'." + (setq compilation-last-buffer (current-buffer)) + (set (make-local-variable 'compilation-error-face) + grep-hit-face) + (set (make-local-variable 'compilation-error-regexp-alist) + grep-regexp-alist) + (set (make-local-variable 'compilation-process-setup-function) + 'egg-grep-process-setup) + (set (make-local-variable 'compilation-disable-input) t) + (set (make-local-variable 'next-error-function) + 'egg-grep-next-error-function)) + +;;;###autoload +(defun egg-grep (level) + (interactive "p") + (let ((git-dir (or (egg-git-dir) + (error "Dir NOT in a git repo: %s" + default-directory))) + (cmd "git --no-pager grep -n ") + rev term) + + (when (> level 15) + (setq rev (egg-read-rev "grep in revision: " "HEAD")) + (when (= (aref rev 0) ?:) + (setq cmd (concat cmd "--cached ")) + (setq rev nil))) + + (when (and (> level 3) (setq term (symbol-at-point))) + (when term + (setq term (symbol-name term)) + (setq cmd (concat cmd term " ")))) + + (when rev + (setq cmd (concat cmd " " rev))) + + (setq cmd + (read-string "run git grep (like this) : " cmd)) + + (compilation-start cmd 'egg-grep-mode + `(lambda (name) + (format "*git-grep@%s*" ,git-dir))))) + diff --git a/egg-grep.elc b/egg-grep.elc new file mode 100644 index 0000000000000000000000000000000000000000..5f3f58288de32fdc867e369897e1be9f7b8d6207 GIT binary patch literal 5862 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" 'face ,face)) + (t `(propertize ,text 'face ,face)))) + +;;(cl-macroexpand '(egg-text blah 'egg-text-3)) + +(defmacro egg-prop (text &rest prop) + "Propertize TEXT with properties list PROP at compile-time or run-time." + (if (stringp text) + (apply 'propertize text + (mapcar (lambda (sym) + (if (consp sym) + (nth 1 sym) + sym)) + prop)) + `(propertize ,text ,@prop))) + +(defalias 'egg-string-at-point 'ffap-string-at-point) +(defalias 'egg-find-file-at-point 'find-file-at-point) + +(defsubst egg-prepend (str prefix &rest other-properties) + "Make STR appear to have prefix PREFIX. +If OTHER-PROPERTIES was non-nil, apply it to STR." + (setq prefix (concat prefix (substring str 0 1))) + (setq str (apply 'propertize str other-properties)) + (put-text-property 0 1 'display prefix str) + str) + +(defsubst egg-commit-contents (rev) + "Retrieve the raw-contents of the commit REV." + (with-temp-buffer + (call-process egg-git-command nil t nil "cat-file" "commit" rev) + (buffer-string))) + +(defsubst egg-commit-message (rev) + "Retrieve the commit message of REV." + (with-temp-buffer + (call-process egg-git-command nil t nil "cat-file" "commit" rev) + (goto-char (point-min)) + (re-search-forward "^\n") + (buffer-substring-no-properties (match-end 0) (point-max)))) + + +(defsubst egg-cmd-to-string-1 (program args) + "Execute PROGRAM and return its output as a string. +ARGS is a list of arguments to pass to PROGRAM." + (with-temp-buffer + (if (= (apply 'call-process program nil t nil args) 0) + (buffer-substring-no-properties + (point-min) (if (> (point-max) (point-min)) + (1- (point-max)) (point-max)))))) + +(defsubst egg-cmd-to-string (program &rest args) + "Execute PROGRAM and return its output as a string. +ARGS is a list of arguments to pass to PROGRAM." + (egg-cmd-to-string-1 program args)) + + +(defsubst egg-git-to-string (&rest args) + "run GIT wih ARGS and return the output as a string." + (egg-cmd-to-string-1 egg-git-command args)) + +(defsubst egg-cmd-ok (program buffer &rest args) + "run PROGRAM with ARGS and insert output into BUFFER at point. +return the t if the exit-code was 0. if BUFFER was t then +current-buffer would be used." + (= (apply 'call-process program nil buffer nil args) 0)) + +(defsubst egg-git-ok (buffer &rest args) + "run GIT with ARGS and insert output into BUFFER at point. +return the t if the exit-code was 0. if BUFFER was t then +current-buffer would be used." + (= (apply 'call-process egg-git-command nil buffer nil args) 0)) + +(defsubst egg-git-region-ok (start end &rest args) + "run GIT with ARGS and insert output into current buffer at point. +return the t if the exit-code was 0. The text between START and END +is used as input to GIT." + (= (apply 'call-process-region start end egg-git-command t t nil args) 0)) + +(defsubst egg-wdir-clean () (egg-git-ok nil "diff" "--quiet")) +(defsubst egg-file-updated (file) + (egg-git-ok nil "diff" "--quiet" "--" file)) +(defsubst egg-file-committed (file) + (egg-git-ok nil "diff" "--quiet" "HEAD" "--" file)) +(defsubst egg-file-index-empty (file) + (egg-git-ok nil "diff" "--quiet" "--cached" "--" file)) +(defsubst egg-index-empty () (egg-git-ok nil "diff" "--cached" "--quiet")) + + +(defsubst egg-git-to-lines (&rest args) + "run GIT with ARGS. +Return the output lines as a list of strings." + (save-match-data + (split-string (or (egg-cmd-to-string-1 egg-git-command args) "") + "[\n]+" t))) + +(defun egg-git-lines-matching (re idx &rest args) + "run GIT with ARGS. +Return the output lines as a list of strings." + (with-temp-buffer + (when (= (apply 'call-process egg-git-command nil t nil args) 0) + (let (lines) + (save-match-data + (goto-char (point-min)) + (while (re-search-forward re nil t) + (setq lines (cons (match-string-no-properties idx) lines))) + lines))))) + +(defun egg-git-lines-matching-multi (re indices &rest args) + "run GIT with ARGS. +Return the output lines as a list of strings." + (with-temp-buffer + (when (= (apply 'call-process egg-git-command nil t nil args) 0) + (let (lines matches) + (save-match-data + (goto-char (point-min)) + (while (re-search-forward re nil t) + (setq matches nil) + (dolist (idx indices) + (when (match-beginning idx) + (setq matches + (cons (cons idx (match-string-no-properties idx)) + matches)))) + (setq lines (cons matches lines))) + lines))))) + +(defsubst egg-file-git-name (file) + "return the repo-relative name of FILE." + (car (egg-git-to-lines "ls-files" "--full-name" "--" file))) + +(defsubst egg-buf-git-name (&optional buf) + "return the repo-relative name of the file visited by BUF. +if BUF was nil then use current-buffer" + (egg-file-git-name (file-truename (buffer-file-name buf)))) + +(defsubst egg-files-git-name (files) + "return the repo-relative name for each file in the list of files FILES." + (delete-duplicates + (apply 'egg-git-to-lines "ls-files" "--full-name" "--" files) + :test 'string-equal)) + +(defsubst egg-unmerged-files () + "return a list of repo-relative names for each unmerged files." + (save-match-data + (delete-duplicates + (mapcar 'car + (mapcar 'last + (mapcar + 'split-string + (egg-git-to-lines "ls-files" "--full-name" "-u")))) + :test 'string-equal))) + +(defsubst egg-local-branches () + "Get a list of local branches. E.g. (\"master\", \"wip1\")." + (egg-git-to-lines "rev-parse" "--symbolic" "--branches")) + +(defsubst egg-local-refs () + "Get a list of local refs. E.g. (\"master\", \"wip1\")." + (egg-git-to-lines "rev-parse" "--symbolic" "--branches" "--tags")) + +(defun egg-remote-branches (&optional raw) + "Get a list of remote branches. E.g. (\"origin/master\", \"joe/fork1\")." + (let ((lst (egg-git-to-lines "rev-parse" "--symbolic" "--remotes"))) + (if raw lst + (mapcar (lambda (full-name) + (let ((tmp (save-match-data (split-string full-name "/")))) + (cons (cadr tmp) (car tmp)))) + lst)))) + +(defsubst egg-rbranch-to-remote (rbranch) + "Return the remote name in the remote-branch RBRANCH. +E.g: `foo' in `foo/bar'" + (and (stringp rbranch) + (> (length rbranch) 0) + (directory-file-name (file-name-directory rbranch)))) + +(defsubst egg-rbranch-name (rbranch) + "Return the ref name in the remote-branch RBRANCH. +E.g: `bar' in `foo/bar'" + (and (stringp rbranch) + (> (length rbranch) 0) + (file-name-nondirectory rbranch))) + +(defsubst egg-short-ref (full-ref) + "Return the short ref name of the full ref name FULL-REF. +like `my_tag' in `refs/tags/my_tag'." + (and (stringp full-ref) + (> (length full-ref) 0) + (file-name-nondirectory full-ref))) + +(defsubst egg-file-as-string-raw (file-name) + (with-temp-buffer + (insert-file-contents-literally file-name) + (buffer-string))) + +(defsubst egg-file-as-string (file-name) + "return the contents of file FILE-NAME as a string." + (with-temp-buffer + (insert-file-contents-literally file-name) + (buffer-substring-no-properties + (point-min) (if (> (point-max) (point-min)) + (1- (point-max)) (point-max))))) + + +(defun egg-pick-file-contents (file-name regexp &rest indices) + "Pick a string out of the contents of the file FILE-NAME. +This function searches for and return the 1st match of REGEXP on the +contents of the file. If indices was not nil, then return the first +successful submatch in the order in INDICES." + (with-temp-buffer + (insert-file-contents-literally file-name) + (goto-char (point-min)) + (when (re-search-forward regexp nil t) + (if (null indices) + (match-string-no-properties 0) + (dolist (idx indices) + (if (match-beginning idx) + (return (match-string-no-properties idx)))))))) + +(defun egg-pick-file-records (file-name start-re end-re) + "Return a list of strings from the contents of the file FILE-NAME. +START-RE is the regexp to match the beginning of a record. +END-RE is the regexp to match the end of a record." + (with-temp-buffer + (insert-file-contents-literally file-name) + (goto-char (point-min)) + (let ((beg (point-min)) + (end (point-max)) + lst) + (save-match-data + (while (and (> end beg) + (not (eobp)) + (re-search-forward start-re nil t)) + (setq beg (match-beginning 0)) + (when (re-search-forward end-re nil t) + (setq end (match-beginning 0)) + (if (> end beg) + (setq lst (cons (buffer-substring-no-properties + beg (match-beginning 0)) + lst))) + (goto-char end)))) + lst))) + +(defsubst egg-is-in-git () + "is the default-directory in a git repo." + (= (call-process egg-git-command nil nil nil "rev-parse" "--git-dir") 0)) + +(defsubst egg-is-dir-in-git (dir) + "is DIR in a git repo." + (let ((default-directory dir)) (egg-is-in-git))) + +(defsubst egg-name-rev (rev) + "get the symbolic name of REV." + (egg-git-to-string "name-rev" "--always" "--name-only" rev)) + +(defsubst egg-describe-rev (rev) + "get the long symbolic name of REV." + (egg-git-to-string "describe" "--always" "--tags" rev)) + +(defsubst egg-sha1 (rev) + "get the SHA1 of REV." + (egg-git-to-string "rev-parse" (concat rev "~0"))) + +(defun egg-read-git-dir () + "call GIT to read the git directory of default-directory." + (let* ((dotgit-parent (and (buffer-file-name) (locate-dominating-file (buffer-file-name) ".git"))) + (dir (or (and dotgit-parent (concat dotgit-parent "/.git")) + (egg-git-to-string "rev-parse" "--git-dir")))) + (if (stringp dir) + (expand-file-name dir)))) + +(defsubst egg-read-dir-git-dir (dir) + "call GIT to read the git directory of DIR." + (let ((default-directory dir)) (egg-read-git-dir))) + +(defvar egg-git-dir nil) +(defsubst egg-git-dir (&optional error-if-not-git) + "return the (pre-read) git-dir of default-directory" + (if (local-variable-p 'egg-git-dir) + egg-git-dir + (set (make-local-variable 'egg-git-dir) + (or (egg-read-git-dir) + (and error-if-not-git + (or (kill-local-variable 'egg-git-dir) t) + (error "Not in a git repository: %s" default-directory)))) + ;; first time, no status yet. + ;; this directory's specific var will be updated by + ;; egg-set-mode-info + (set (intern (concat "egg-" egg-git-dir "-HEAD")) " Egg") + egg-git-dir)) + +(defsubst egg-buf-git-dir (buffer) + "return the (pre-read) git-dir of BUFFER." + (with-current-buffer buffer + (egg-git-dir))) + +(defun egg-HEAD () + "return HEAD. Either a symbolic ref or a sha1." + (let* ((git-dir (egg-git-dir))) + (if git-dir + (egg-pick-file-contents (concat git-dir "/HEAD") + "^ref: refs/heads/\\(.+\\)\\|^\\([0-9a-f]+\\)" 1 2)))) + +(defun egg-all-refs () + "Get a list of all refs." + (append (egg-git-to-lines "rev-parse" "--symbolic" + "--branches" "--tags" "--remotes") + (delq nil + (mapcar + (lambda (head) + (if (file-exists-p (concat (egg-git-dir) "/" head)) + head)) + '("HEAD" "ORIG_HEAD" "MERGE_HEAD" "FETCH_HEAD"))))) + +(defun egg-ref-type-alist () + "Build an alist of (REF-NAME . :type) cells." + (mapcar (lambda (ref-desc) + (cons (cdr (assq 5 ref-desc)) + (cond ((assq 2 ref-desc) :head) + ((assq 3 ref-desc) :tag) + ((assq 4 ref-desc) :remote)))) + (egg-git-lines-matching-multi + "^.+ \\(refs/\\(?:\\(heads\\)\\|\\(tags\\)\\|\\(remotes\\)\\)/\\(\\([^/\n]+/\\)?[^/\n]+\\)\\)$" + ;; 1: full-name + ;; 2: head + ;; 3: tag + ;; 4: remote + ;; 5: name + ;; 6: remote-host + '(1 2 3 4 5 6) "show-ref"))) + +(defsubst egg-tooltip-func () + (if egg-enable-tooltip 'egg-buffer-help-echo)) + +(defun egg-full-ref-decorated-alist (head-properties + tag-properties + atag-properties + remote-ref-properties + remote-site-properties) + "Build an alist of (ref . :type) cells. +A ref string of a head will be decorated with head-PROPERTIES. A +ref string of a tag will be decorated with TAG-PROPERTIES or +ATAG-PROPERTIES. A ref string of a remote will be formatted with +REMOTE-REF-PROPERTIES and REMOTE-SITE-PROPERTIES." + (let ((refs-desc-list + (egg-git-lines-matching-multi + "^.+ \\(refs/\\(?:\\(heads\\)\\|\\(tags\\)\\|\\(remotes\\)\\)/\\(\\([^/\n]+/\\)?[^/\n{}]+\\)\\)\\(\\^{}\\)?$" + ;; 1: full-name + ;; 2: head + ;; 3: tag + ;; 4: remote + ;; 5: name + ;; 6: remote-host + ;; 7: is annotated tag + '(1 2 3 4 5 6 7) "show-ref" "-d")) + annotated-tags) + ;; remove the annotated tags from the list + (setq refs-desc-list + (delq nil + (mapcar (lambda (desc) + (if (not (assq 7 desc)) + ;; not an annotated tag + desc + (setq annotated-tags + (cons (cdr (assq 1 desc)) + annotated-tags)) + nil)) + refs-desc-list))) + ;; decorate the ref alist + (mapcar (lambda (desc) + (let ((full-name (cdr (assq 1 desc))) + (name (cdr (assq 5 desc))) + (remote (cdr (assq 6 desc)))) + (cond ((assq 2 desc) + ;; head + (cons full-name + (apply 'propertize name + :ref (cons name :head) + head-properties))) + ((assq 3 desc) + ;; tag + (cons full-name + (apply 'propertize name + :ref (cons name :tag) + (if (member full-name annotated-tags) + atag-properties + tag-properties)))) + ((assq 4 desc) + ;; remote + (cons full-name + (concat + (if (stringp remote) + (apply 'propertize remote + :ref (cons name :remote) + remote-site-properties) + ;; svn has no remote name + "") + (apply 'propertize (substring name (length remote)) + :ref (cons name :remote) + remote-ref-properties))))))) + refs-desc-list))) + + + +(defun egg-complete-rev (string &optional ignored all) + "Do revision completion" + (save-match-data + (cond ((string-match "\\`:[0-3]*" string) ;; stages + (funcall (if all 'all-completions 'try-completion) + string '(":0" ":1" ":2" ":3"))) + + ;; rev^, rev~10 etc. + ((string-match "[\\^~][\\^~0-9]*\\'" string) + ;; check with rev-parse + (if (egg-git-ok nil "rev-parse" string) + ;; rev-parse ok + (if all + ;; fixme: how to do a full expansion? + (list string) + ;; match + string))) + + ;; normal rev name + (t (let ((matches + ;; match all types of refs + (egg-git-to-lines "for-each-ref" "--format=%(refname)" + (concat "refs/*/" string "*") + (concat "refs/*/" string "*/*"))) + prefix) + ;; get the short name + ;; with 1.6.x: for-each-ref" "--format=%(refname=short) + (setq matches + (mapcar (lambda (long) + (string-match + "\\`refs/\\(?:heads\\|tags\\|remotes\\)/\\(.+\\)\\'" + long) + (match-string-no-properties 1 long)) + matches)) + ;; do the completion + (setq prefix + (funcall (if all 'all-completions 'try-completion) + string + (nconc (directory-files (egg-git-dir) + nil "HEAD") + matches))) + (cond (all prefix) + ((stringp prefix) prefix) + ((null prefix) nil) + (t string))))))) + +(defsubst egg-get-symbolic-HEAD (&optional file) + ;; get the symbolic name of HEAD + (setq file (or file (concat (egg-git-dir) "/HEAD"))) + (egg-pick-file-contents file + "^ref: refs/heads/\\(.+\\)" + 1)) + +(defsubst egg-get-full-symbolic-HEAD (&optional file) + ;; get the symbolic full name of HEAD + (setq file (or file (concat (egg-git-dir) "/HEAD"))) + (egg-pick-file-contents file + "^ref: \\(refs/heads/.+\\)" + 1)) + +(defsubst egg-get-current-sha1 () + (or (egg-git-to-string "rev-parse" "--verify" "-q" "HEAD") + "0000000000000000000000000000000000000000")) + +(defsubst egg-set-mode-info (state) + "Set the mode-line string for buffers visiting files in the current repo. +The string is built based on the current state STATE." + (set (intern (concat "egg-" egg-git-dir "-HEAD")) + (format " Git:%s" (cond ((plist-get state :rebase-dir) + "(rebasing)") + ((plist-get state :merge-heads) + "(merging)") + ((plist-get state :branch) + (plist-get state :branch)) + (t "(detached)"))))) + +(defsubst egg-get-rebase-merge-state (rebase-dir) + "Build a plist of rebase info of REBASE-DIR. +this is for rebase -m variant." + (list :rebase-dir rebase-dir + :rebase-head + (egg-name-rev (egg-file-as-string (concat rebase-dir "head-name"))) + :rebase-upstream + (egg-describe-rev (egg-file-as-string (concat rebase-dir "onto_name"))) + :rebase-step ;; string-to-number? + (egg-file-as-string (concat rebase-dir "msgnum")) + :rebase-num ;; string-to-number? + (egg-file-as-string (concat rebase-dir "end")))) + +(defsubst egg-get-rebase-interactive-state (rebase-dir) + "Build a plist of rebase info of REBASE-DIR. +this is for rebase -i variant." + (list :rebase-dir rebase-dir + :rebase-head + (egg-name-rev (egg-file-as-string (concat rebase-dir "head-name"))) + :rebase-upstream + (egg-describe-rev (egg-file-as-string (concat rebase-dir "onto"))) + :rebase-num + (length + (egg-pick-file-records (concat rebase-dir "git-rebase-todo.backup") + "^[pes]" "$")) + :rebase-step + (if (file-exists-p (concat rebase-dir "done")) + (length (egg-pick-file-records (concat rebase-dir "done") + "^[pes]" "$")) + 0) + :rebase-cherry + (if (file-exists-p (concat rebase-dir "done")) + (car (egg-pick-file-records + (concat rebase-dir "done") + "^[pes]" "$"))))) + +(defsubst egg-git-rebase-dir (&optional git-dir) + (concat (or git-dir (egg-git-dir)) "/" egg-git-rebase-subdir "/")) + +(defsubst egg-rebase-author-info (rebase-dir) + "Retrieve an alist of commit environment variables of the current +cherry in REBASE-DIR." + (mapcar (lambda (lst) + ;; chop the ' ' + (setcar (cdr lst) (substring (cadr lst) 1 -1)) + lst) + (mapcar (lambda (line) + ;; name-value split + (save-match-data (split-string line "=" t))) + ;; grab the GIT_xxx=yyy + (egg-pick-file-records (concat rebase-dir "author-script") + "^GIT_\\(.+\\)" "$")))) + +(defsubst egg-interactive-rebase-in-progress () + "Is an interactive rebase in progress in the current repo?" + (file-exists-p (concat (egg-git-dir) "/" egg-git-rebase-subdir + "/interactive") )) + +(defvar egg-internal-current-state nil) +(defun egg-get-repo-state (&optional extras) + "Retrieve current repo's state as a plist. +The properties: +:gitdir :head :branch :sha1 :merge-heads :rebase-dir :rebase-head +:rebase-upstream :rebase-step :rebase-num :rebase-cherry + +EXTRAS contains the extra properties to retrieve: :staged :unstaged + +if EXTRAS contains :error-if-not-git then error-out if not a git repo. +" + (let* ((git-dir (egg-git-dir (memq :error-if-not-git extras))) + (head-file (concat git-dir "/HEAD")) + (merge-file (concat git-dir "/MERGE_HEAD")) + (branch (egg-get-symbolic-HEAD head-file)) + (branch-full-name (egg-get-full-symbolic-HEAD head-file)) + (sha1 (egg-get-current-sha1)) + (merge-heads + (mapcar 'egg-name-rev + (if (file-readable-p merge-file) + (egg-pick-file-records merge-file "^" "$")))) + (rebase-dir + (if (file-directory-p (concat git-dir "/" egg-git-rebase-subdir)) + (concat git-dir "/" egg-git-rebase-subdir "/"))) + (is-rebase-interactive + (file-exists-p (concat rebase-dir "interactive"))) + (rebase-state + (when rebase-dir + (if is-rebase-interactive + (egg-get-rebase-interactive-state rebase-dir) + (egg-get-rebase-merge-state rebase-dir)))) + (state (nconc (list :gitdir git-dir + :head branch-full-name + :branch branch + :sha1 sha1 + :merge-heads merge-heads) + rebase-state)) + files) + (dolist (req extras) + (cond ((eq req :unstaged) + (setq files (egg-git-to-lines "diff" "--name-only")) + (setq state (nconc (list :unstaged files) state)) + (when (and files (stringp (car files))) + (setq state (nconc (list :unmerged (egg-unmerged-files)) + state)))) + ((eq req :staged) + (setq state + (nconc (list :staged + (egg-git-to-lines "diff" "--cached" + "--name-only")) + state))))) + ;; update mode-line + (egg-set-mode-info state) + state)) + +(defsubst egg-repo-state (&rest args) + "return the cached repo state or re-read it. +if ARGS contained :force then ignore the cached state." + (or (unless (memq :force args) egg-internal-current-state) + (egg-get-repo-state args))) + +(defsubst egg-repo-clean (&optional state) + "Whether the current repos is clean base on the current repo state. +use STATE as repo state if it was not nil. Otherwise re-read the repo state." + (unless state + (setq state (egg-repo-state :staged :unstaged))) + (and + (null (plist-get state :rebase-num)) + (null (plist-get state :merge-heads)) + (not (if (memq :unstaged state) + (plist-get state :unstaged) + (egg-wdir-clean))) + (not (if (memq :staged state) + (plist-get state :staged) + (egg-index-empty))))) + +(defsubst egg-current-branch (&optional state) + "The current symbolic value of HEAD. i.e. name of a branch. if STATE +was not nil then use it as repo state instead of re-read from disc." + (plist-get (or state (egg-repo-state)) :branch)) + +(defsubst egg-current-sha1 (&optional state) + "The immutable sha1 of HEAD. if STATE was not nil then use it +as repo state instead of re-read from disc." + (plist-get (or state (egg-repo-state)) :sha1)) + +(defsubst egg-head (&optional state) + "a cons cell (branch . sha1) of HEAD. if STATE was not nil then use it +as repo state instead of re-read from disc." + (if (egg-git-dir) + (let ((state (or state (egg-repo-state)))) + (cons (egg-current-sha1 state) + (egg-current-branch state))))) + +(defun egg-pretty-head-string (&optional state) + "Pretty description of HEAD. if STATE was not nil then use it +as repo state instead of re-read from disc." + (let* ((state (or state (egg-repo-state))) + (branch (plist-get state :branch)) + (merge-heads (plist-get state :merge-heads)) + (rebase-head (plist-get state :rebase-head)) + (rebase-upstream (plist-get state :rebase-upstream)) + (sha1 (plist-get state :sha1))) + (cond ((and branch merge-heads) + (concat "Merging to " branch " from: " + (mapconcat 'identity merge-heads ","))) + (merge-heads + (concat "Merging to " (egg-name-rev sha1) " from: " + (mapconcat 'identity merge-heads ","))) + ((and rebase-head rebase-upstream) + (format "Rebasing %s onto %s" rebase-head rebase-upstream)) + (branch branch) + (t (concat "Detached HEAD: " (egg-describe-rev sha1)))))) + +(defsubst egg-pretty-head-name (&optional state) + "Pretty name for HEAD. if STATE was not nil then use it +as repo state instead of re-read from disc." + (let* ((state (or state (egg-repo-state))) + (branch (plist-get state :branch))) + (or branch (egg-describe-rev (plist-get state :sha1))))) + + +(defsubst egg-config-section-raw (type &optional name) + (egg-pick-file-contents (concat (egg-git-dir) "/config") + (concat "^" + (if name + (format "\\[%s \"%s\"\\]" type name) + (format "\\[%s\\]" type)) + "\n" + "\\(\\(?:\t.+\n\\)+\\)") + 1)) + +(defsubst egg-config-section (type &optional name) + (save-match-data + (mapcar + (lambda (line) + (split-string line "[ =]+" t)) + (split-string (or (egg-config-section-raw type name) "") + "[\t\n]+" t)))) + +(defun egg-config-get-all (file type) + (interactive "fFilename: ") + (save-match-data + (mapcar (lambda (rec) + (let ((key (car rec)) + (infos (cdr rec))) + (cons (progn (string-match "\"\\(.+\\)\"" key) + (match-string-no-properties 1 key)) + (mapcar (lambda (attr) + (split-string attr "[ =]+" t)) + infos)))) + (mapcar (lambda (str) + (split-string str "[\t\n]+" t)) + (egg-pick-file-records file + (concat "^\\[" type " \"") + "^\\[\\|\\'"))))) + +(defsubst egg-config-get-all-branches () + (egg-config-get-all (concat (egg-git-dir) "/config") "branch")) + +(defsubst egg-config-get-all-remotes () + (egg-config-get-all (concat (egg-git-dir) "/config") "remote")) + +(defsubst egg-config-get-all-remote-names () + (mapcar 'car (egg-config-get-all-remotes))) + +(defsubst egg-config-get (type attr &optional name) + (and (egg-git-dir) + (cadr (assoc attr (egg-config-section type name))))) + +(defun egg-tracking-target (branch &optional mode) + (let ((remote (egg-config-get "branch" "remote" branch)) + (rbranch (egg-config-get "branch" "merge" branch))) + (when (stringp rbranch) + (setq rbranch (egg-rbranch-name rbranch)) + (cond ((null mode) (concat remote "/" rbranch)) + ((eq :name-only mode) rbranch) + (t (cons rbranch remote)))))) + + +(defsubst egg-read-rev (prompt &optional default) + "Query user for a revision using PROMPT. DEFAULT is the default value." + (completing-read prompt 'egg-complete-rev nil nil default)) + +(defsubst egg-read-remote (prompt &optional default) + "Query user for a remote using PROMPT. DEFAULT is the default value." + (completing-read prompt (egg-config-get-all-remote-names) nil t default)) + +;;;======================================================== +;;; Async Git process +;;;======================================================== + +(defsubst egg-async-process () + (let* ((buffer (get-buffer-create "*egg-process*")) + (proc (get-buffer-process buffer))) + (if (and (processp proc) ;; is a process + (not (eq (process-status proc) 'exit)) ;; not finised + (= (process-exit-status proc) 0)) ;; still running + proc))) + +(defun egg-async-do (exit-code func-args args) + "Run GIT asynchronously with ARGS. +if EXIT code is an exit-code from GIT other than zero but considered +success." + (let ((dir (file-name-directory (egg-git-dir))) + (buf (get-buffer-create "*egg-process*")) + (inhibit-read-only inhibit-read-only) + (accepted-msg (and (integerp exit-code) + (format "exited abnormally with code %d" + exit-code))) + proc) + (setq proc (get-buffer-process buf)) + (when (and (processp proc) ;; is a process + (not (eq (process-status proc) 'exit)) ;; not finised + (= (process-exit-status proc) 0)) ;; still running + (error "EGG: %s is already running!" (process-command proc))) + (with-current-buffer buf + (setq inhibit-read-only t) + (setq default-directory dir) + ;;(erase-buffer) + (widen) + (goto-char (point-max)) + (insert "EGG-GIT-CMD:\n") + (insert (format "%S\n" args)) + (insert "EGG-GIT-OUTPUT:\n") + (setq proc (apply 'start-process "egg-git" buf egg-git-command args)) + (setq mode-line-process " git") + (when (and (consp func-args) (functionp (car func-args))) + (process-put proc :callback-func (car func-args)) + (process-put proc :callback-args (cdr func-args))) + (when (stringp accepted-msg) + (process-put proc :accepted-msg accepted-msg) + (process-put proc :accepted-code exit-code)) + (process-put proc :cmds (cons egg-git-command args)) + (set-process-sentinel proc #'egg-process-sentinel)) + proc)) + +(defsubst egg-async-0 (func-args &rest args) + (egg-async-do nil func-args args)) + +(defsubst egg-async-1 (func-args &rest args) + (egg-async-do 1 func-args args)) + +(defvar egg-async-process nil) +(defvar egg-async-cmds nil) +(defvar egg-async-exit-msg nil) + +(defun egg-process-sentinel (proc msg) + (let ((exit-code (process-get proc :accepted-code)) + (accepted-msg (process-get proc :accepted-msg)) + (callback-func (process-get proc :callback-func)) + (callback-args (process-get proc :callback-args)) + (cmds (process-get proc :cmds))) + (cond ((string= msg "finished\n") + (message "EGG: git finished.")) + ((string= msg "killed\n") + (message "EGG: git was killed.")) + ((and accepted-msg (string-match accepted-msg msg)) + (message "EGG: git exited with code: %d." exit-code)) + ((string-match "exited abnormally" msg) + (message "EGG: git failed.")) + (t (message "EGG: git is weird!"))) + (with-current-buffer (process-buffer proc) + (setq mode-line-process nil) + (widen) + (goto-char (point-max)) + (re-search-backward "^EGG-GIT-CMD:" nil t) + ;; Narrow to the last command + (narrow-to-region (point) (point-max)) + (if (functionp callback-func) + (let ((egg-async-process proc) + (egg-async-cmds cmds) + (egg-async-exit-msg msg)) + (apply callback-func callback-args)))))) + +;;;======================================================== +;;; Blame utils +;;;======================================================== + +(defconst egg-blame-map + (let ((map (make-sparse-keymap "Egg:Blame"))) + (define-key map (kbd "l") 'egg-blame-locate-commit) + (define-key map (kbd "RET") 'egg-blame-locate-commit) + (define-key map (kbd "q") 'egg-file-toggle-blame-mode) + map) + "Keymap for an annotated section.\\{egg-blame-map}") + + +(defun egg-parse-git-blame (target-buf blame-buf &optional ov-attributes) + "Parse blame-info in buffer BLAME-BUF and decorate TARGET-BUF buffer. +OV-ATTRIBUTES are the extra decorations for each blame chunk." + (save-match-data + (let ((blank (egg-text " " 'egg-blame)) + (nl (egg-text "\n" 'egg-blame)) + (commit-hash (make-hash-table :test 'equal :size 577)) + commit commit-info old-line new-line num old-file subject author + info ov beg end blame) + (with-current-buffer blame-buf + (goto-char (point-min)) + ;; search for a ful commit info + (while (re-search-forward "^\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)$" nil t) + (setq commit (match-string-no-properties 1) + old-line (string-to-number + (match-string-no-properties 2)) + new-line (string-to-number + (match-string-no-properties 3)) + num (string-to-number + (match-string-no-properties 4))) + ;; was this commit already seen (and stored in the hash)? + (setq commit-info (gethash commit commit-hash)) + ;; Nope, this is the 1st time, the full commit-info follow. + (unless commit-info + (re-search-forward "^author \\(.+\\)$") + (setq author (match-string-no-properties 1)) + (re-search-forward "^summary \\(.+\\)$") + (setq subject (match-string-no-properties 1)) + (re-search-forward "^filename \\(.+\\)$") + (setq old-file (match-string-no-properties 1)) + (setq commit-info (nconc + (list :sha1 commit :author author + :subject subject :file old-file) + ov-attributes)) + ;; save it in the hash + (puthash commit commit-info commit-hash)) + ;; add the current blame-block into the list INFO. + (setq info (cons (list old-line new-line num commit-info) + info)))) + ;; now do from beginning + (setq info (nreverse info)) + (with-current-buffer target-buf + ;; for every blame chunk + (dolist (chunk info) + (setq commit-info (nth 3 chunk) + old-line (nth 0 chunk) + new-line (nth 1 chunk) + num (nth 2 chunk) + commit (plist-get commit-info :sha1) + author (plist-get commit-info :author) + subject (plist-get commit-info :subject)) + + (goto-line new-line) + (setq beg (line-beginning-position) + end (save-excursion + (forward-line num) + (line-beginning-position))) + ;; mark the blame chunk + (put-text-property beg end :blame chunk) + + ;; make an overlay with blame info as 'before-string + ;; on the current chunk. + (setq ov (make-overlay beg end)) + (overlay-put ov :blame chunk) + (setq blame (concat + (egg-text (substring-no-properties commit 0 8) + 'egg-blame) + blank + (egg-text (format "%-20s" author) + 'egg-blame-culprit) + blank + (egg-text subject 'egg-blame-subject) + blank nl)) + (overlay-put ov 'before-string blame) + (overlay-put ov 'local-map egg-blame-map)))))) + +(defsubst egg-file-buffer-blame-off (buffer) + (save-excursion + (save-restriction + (with-current-buffer buffer + (widen) + (mapc (lambda (ov) + (if (overlay-get ov :blame) + (delete-overlay ov))) + (overlays-in (point-min) (point-max))))))) + +(defun egg-file-buffer-blame-on (buffer &rest ov-attributes) + (egg-file-buffer-blame-off buffer) + (save-excursion + (with-current-buffer buffer + (save-restriction + (with-temp-buffer + (when (egg-git-ok t "blame" "--porcelain" "--" + (file-name-nondirectory + (buffer-file-name buffer))) + (egg-parse-git-blame buffer (current-buffer) + ov-attributes))))))) + +(defun egg-blame-locate-commit (pos &optional all) + (interactive "d\nP") + "Jump to a commit in the branch history from an annotated blame section. + + With prefix argument, the history of all refs is used." + (let ((overlays (overlays-at pos)) + sha1) + (dolist (ov overlays) + (if (overlay-get ov :blame) + (setq sha1 (plist-get (nth 3 (overlay-get ov :blame)) :sha1)))) + (if sha1 + (let (commit-pos) + (egg-log all) + (setq commit-pos (point-min)) + (while (and commit-pos + (not (equal (get-text-property commit-pos :commit) sha1))) + (setq commit-pos (next-single-property-change commit-pos :commit))) + (if commit-pos + (progn + (egg-log-buffer-goto-pos commit-pos) + (recenter))))))) + +;;;======================================================== +;;; Diff/Hunk +;;;======================================================== + +(defun egg-mouse-do-command (event cmd) + (let* ((window (posn-window (event-end event))) + (buffer (and window (window-buffer window))) + (position (posn-point (event-end event)))) + (when (bufferp buffer) + (save-window-excursion + (save-excursion + (select-window window) + (with-current-buffer buffer + (goto-char position) + (call-interactively cmd))))))) + +(defun egg-mouse-hide-show-cmd (event) + (interactive "e") + (egg-mouse-do-command event 'egg-section-cmd-toggle-hide-show)) + +(defconst egg-hide-show-map + (let ((map (make-sparse-keymap "Egg:HideShow"))) + (define-key map (kbd "h") 'egg-section-cmd-toggle-hide-show) + (define-key map (kbd "H") 'egg-section-cmd-toggle-hide-show-children) + (define-key map [mouse-2] 'egg-mouse-hide-show-cmd) + map) + "Keymap for a section than can be hidden/shown.\\{egg-hide-show-map}") + +(defconst egg-section-map + (let ((map (make-sparse-keymap "Egg:Section"))) + (set-keymap-parent map egg-hide-show-map) + (define-key map (kbd "n") 'egg-buffer-cmd-navigate-next) + (define-key map (kbd "p") 'egg-buffer-cmd-navigate-prev) + map) + "Keymap for a section in sequence that can be navigated back and forth. +\\{egg-section-map}") + +(defconst egg-diff-section-map + (let ((map (make-sparse-keymap "Egg:Diff"))) + (set-keymap-parent map egg-section-map) + (define-key map (kbd "RET") 'egg-diff-section-cmd-visit-file-other-window) + (define-key map (kbd "f") 'egg-diff-section-cmd-visit-file) + (define-key map (kbd "=") 'egg-diff-section-cmd-ediff) + map) + "Keymap for a diff section in sequence of deltas. +\\{egg-diff-section-map}") + +(defconst egg-staged-diff-section-map + (let ((map (make-sparse-keymap "Egg:StagedDiff"))) + (set-keymap-parent map egg-diff-section-map) + (define-key map (kbd "=") 'egg-staged-section-cmd-ediff3) + (define-key map (kbd "s") 'egg-diff-section-cmd-unstage) + (define-key map [C-down-mouse-2] 'egg-status-popup-staged-diff-menu) + (define-key map [C-mouse-2] 'egg-status-popup-staged-diff-menu) + + map) + "Keymap for a diff section in sequence of staged deltas. +\\{egg-staged-diff-section-map}") + +(defconst egg-wdir-diff-section-map + (let ((map (make-sparse-keymap "Egg:WdirDiff"))) + (set-keymap-parent map egg-diff-section-map) + (define-key map (kbd "u") 'egg-diff-section-cmd-undo) + map) + "Keymap for a diff section in sequence of deltas between the workdir and +the index. \\{egg-wdir-diff-section-map}") + +(defconst egg-unstaged-diff-section-map + (let ((map (make-sparse-keymap "Egg:UnstagedDiff"))) + (set-keymap-parent map egg-wdir-diff-section-map) + (define-key map (kbd "=") 'egg-unstaged-section-cmd-ediff) + (define-key map (kbd "s") 'egg-diff-section-cmd-stage) + + (define-key map [C-down-mouse-2] 'egg-status-popup-unstaged-diff-menu) + (define-key map [C-mouse-2] 'egg-status-popup-unstaged-diff-menu) + + map) + "Keymap for a diff section in sequence of unstaged deltas. +\\{egg-unstaged-diff-section-map}") + +(defconst egg-unmerged-diff-section-map + (let ((map (make-sparse-keymap "Egg:UnmergedDiff"))) + (set-keymap-parent map egg-unstaged-diff-section-map) + (define-key map (kbd "=") 'egg-unmerged-section-cmd-ediff3) + map) + "Keymap for a diff section in sequence of unmerged deltas. +\\{egg-unmerged-diff-section-map}") + +(defconst egg-hunk-section-map + (let ((map (make-sparse-keymap "Egg:Hunk"))) + (set-keymap-parent map egg-section-map) + (define-key map (kbd "RET") 'egg-hunk-section-cmd-visit-file-other-window) + (define-key map (kbd "=") 'egg-diff-section-cmd-ediff) + (define-key map (kbd "f") 'egg-hunk-section-cmd-visit-file) + map) + "Keymap for a hunk in a diff section. \\{egg-hunk-section-map}") + +(defconst egg-staged-hunk-section-map + (let ((map (make-sparse-keymap "Egg:StagedHunk"))) + (set-keymap-parent map egg-hunk-section-map) + (define-key map (kbd "=") 'egg-staged-section-cmd-ediff3) + (define-key map (kbd "s") 'egg-hunk-section-cmd-unstage) + + (define-key map [C-down-mouse-2] 'egg-status-popup-staged-hunk-menu) + (define-key map [C-mouse-2] 'egg-status-popup-staged-hunk-menu) + + map) + "Keymap for a hunk in a staged diff section. +\\{egg-staged-hunk-section-map}") + +(defconst egg-wdir-hunk-section-map + (let ((map (make-sparse-keymap "Egg:WdirHunk"))) + (set-keymap-parent map egg-hunk-section-map) + (define-key map (kbd "u") 'egg-hunk-section-cmd-undo) + map) + "Keymap for a hunk in a diff section between the workdir and the index. +\\{egg-wdir-hunk-section-map}") + +(defconst egg-unstaged-hunk-section-map + (let ((map (make-sparse-keymap "Egg:UnstagedHunk"))) + (set-keymap-parent map egg-wdir-hunk-section-map) + (define-key map (kbd "=") 'egg-unstaged-section-cmd-ediff) + (define-key map (kbd "s") 'egg-hunk-section-cmd-stage) + + (define-key map [C-down-mouse-2] 'egg-status-popup-unstaged-hunk-menu) + (define-key map [C-mouse-2] 'egg-status-popup-unstaged-hunk-menu) + + map) + "Keymap for a hunk in a unstaged diff section. +\\{egg-unstaged-hunk-section-map}") + +(defconst egg-unmerged-hunk-section-map + (let ((map (make-sparse-keymap "Egg:UnmergedHunk"))) + ;; no hunking staging in unmerged file + (set-keymap-parent map egg-wdir-hunk-section-map) + (define-key map (kbd "=") 'egg-unmerged-section-cmd-ediff3) + map) + "Keymap for a hunk in a unmerged diff section. +\\{egg-unmerged-hunk-section-map}") + +(defun list-tp () + (interactive) + (message "tp: %S" (text-properties-at (point)))) + +(defun list-nav () + (interactive) + (message "nav: %c:%s-%c:%s" + (preceding-char) + (get-text-property (1- (point)) :navigation) + (following-char) + (get-text-property (point) :navigation))) + +(defsubst egg-navigation-at-point () + (get-text-property (point) :navigation)) + +(defsubst egg-invisible-spec-at-point () + (get-text-property (point) 'invisible)) + +(defsubst egg-hunk-at-point () + (get-text-property (point) :hunk)) + +(defsubst egg-diff-at-point () + (get-text-property (point) :diff)) + +(defsubst egg-point-in-section (section-id) + (eq (get-text-property (point) :section) section-id)) + +(defsubst egg-safe-search (re limit &optional no) + (save-excursion + (save-match-data + (and (re-search-forward re limit t) + (match-beginning (or no 0)))))) + +(defsubst egg-safe-search-pickup (re &optional limit no) + (save-excursion + (save-match-data + (and (re-search-forward re limit t) + (match-string-no-properties (or no 0)))))) + +(defsubst egg-decorate-diff-header (beg end line-beg line-end) + (put-text-property line-beg (1+ beg) + 'display + (egg-text + (concat "\n" + (buffer-substring-no-properties beg + (1+ beg))) + 'egg-diff-file-header)) + (put-text-property (1+ beg) end 'face 'egg-diff-file-header) + (put-text-property (1+ beg) end 'help-echo (egg-tooltip-func))) + +(defsubst egg-decorate-cc-diff-header (beg end line-beg line-end) + (put-text-property line-beg (1+ beg) + 'display + (egg-text + (concat "\n" + (buffer-substring-no-properties beg + (1+ beg))) + 'egg-unmerged-diff-file-header)) + (put-text-property (1+ beg) end 'face 'egg-unmerged-diff-file-header) + (put-text-property (1+ beg) end 'help-echo (egg-tooltip-func))) + +(defsubst egg-decorate-diff-index-line (beg end line-beg line-end) + (put-text-property (1- line-beg) beg 'display " -- ") + (put-text-property beg end 'face 'egg-diff-none)) + +(defsubst egg-decorate-hunk-header (beg end line-beg line-end) + (put-text-property beg end 'face 'egg-diff-hunk-header) + (put-text-property end line-end 'face 'egg-diff-none) + (put-text-property beg end 'help-echo (egg-tooltip-func))) + +(defvar egg-internal-buffer-obarray nil) + +(defsubst egg-make-navigation (parent child) + "Make a symbolic and unique navigation id. +return a symbol PARENT-CHILD from an internal obarray." + (unless (vectorp egg-internal-buffer-obarray) + (error "Arrg! egg-internal-buffer-obarray is not an obarray!")) + (intern (format "%s-%s" parent child) egg-internal-buffer-obarray)) + +(defsubst egg-do-compute-navigation (section pos) + "Come up with a symbolic and unique navigation id for +section SECTION at position POS." + (egg-make-navigation (get-text-property pos :navigation) + (if (consp section) + (car section) + section))) + +(defun egg-compute-navigation (ignored-1 section pos ignored-2) + "Come up with a symbolic and unique navigation id for +section SECTION at position POS." + (egg-do-compute-navigation section pos)) + +(defun egg-delimit-section (sect-type section beg end + &optional inv-beg + keymap navigation) + "Mark section for navigation and add local/context keymap. +SECT-TYPE is the type of the section (usually a :symbol). +SECTION is the name of the section (usually a string). BEG and +END are limits of the section. INV-BEG is the position after the +position that would remain visible when the section is hidden. +KEYMAP is the local/context keymap for the section. +NAVIGATION is the navigation id of the section. NAVIGATION can also +a function to call to compute the navigation id of the section." + (let ((nav (cond ((functionp navigation) + (funcall navigation sect-type section beg end)) + ((null navigation) beg) + (t navigation)))) + (put-text-property beg end :sect-type sect-type) + (put-text-property beg end sect-type section) + (put-text-property beg end :navigation nav) + (when (keymapp keymap) + (put-text-property beg end 'keymap keymap)) + (when (integer-or-marker-p inv-beg) + (let ((current-inv (get-text-property inv-beg 'invisible))) + (add-to-list 'current-inv nav t) + (put-text-property inv-beg (1- end) 'invisible current-inv))))) + +(defsubst egg-make-hunk-info (name beg end diff) + "Build a hunk info NAME from BEG to END based on DIFF. +Hunk info contains name and posistions of the hunk. Positions are offsets +from DIFF because it can the whole diff can be pushed around inside +the buffer." + (let ((b (nth 1 diff))) + (list name (- beg b) (- end b)))) + +(defsubst egg-make-diff-info (name beg end head-end) + "Build a diff info NAME from BEG to END. HEAD-END is the end position +of the diff header. + +Diff info contains name and posistions of the diff. The beginning position +is stored as a marker and the others are offset from the beginning posistion + because the whole diff can be pushed around inside the buffer." + (let ((b (make-marker))) + (set-marker b beg) + ;; no insertion indo the diff + (set-marker-insertion-type b t) + ;; all other posistions are offsets from B. + (list name b (- end beg) (- head-end beg)))) + +(defun egg-decorate-diff-sequence (args) + "Decorate a sequence of deltas. ARGS is a plist containing the +positions of the sequence as well as the decorations. + +:begin :end :diff-map :hunk-map :cc-diff-map :cc-hunk-map +:conflict-map :src-prefix :dst-prefix +" + (let* ((beg (plist-get args :begin)) + (end (plist-get args :end)) + (diff-map (plist-get args :diff-map)) + (hunk-map (plist-get args :hunk-map)) + (cc-diff-map (plist-get args :cc-diff-map)) + (cc-hunk-map (plist-get args :cc-hunk-map)) + (conflict-map (plist-get args :conflict-map)) + (a (plist-get args :src-prefix)) + (b (plist-get args :dst-prefix)) + + ;; the sub match id of the regexp below + (diff-no 1) + (cc-diff-no 2) + (hunk-no 3) + (cc-hunk-no 4) + (src-no 5) + (dst-no 6) + (index-no 7) + (conf-beg-no 8) + (conf-div-no 9) + (conf-end-no 10) + (del-no 11) + (add-no 12) + (none-no 13) + + (regexp + (concat "^\\(?:" + "diff --git " a ".+" b "\\(.+\\)\\|" ;1 diff header + "diff --cc \\(.+\\)\\|" ;2 cc-diff header + "\\(@@ .+@@\\).*\\|" ;3 hunk + "\\(@@@ .+@@@\\).*\\|" ;4 cc-hunk + "--- " a "\\(.+\\)\\|" ;5 src + "\\+\\+\\+ " b "\\(.+\\)\\|" ;6 dst + "index \\(.+\\)\\|" ;7 index + "\\+\\+<<<<<<< \\(.+\\):.+\\|" ;8 conflict start + "\\(\\+\\+=======\\)\\|" ;9 conflict div + "\\+\\+>>>>>>> \\(.+\\):.+\\|" ;10 conflict end + "\\(-.*\\)\\|" ;11 del + "\\(\\+.*\\)\\|" ;12 add + "\\( .*\\)" ;13 none + "\\)$")) + + ;; where the hunk end? + (hunk-end-re "^\\(?:diff\\|@@\\)") + ;; where the diff end? + (diff-end-re "^diff ") + + sub-beg sub-end head-end m-b-0 m-e-0 m-b-x m-e-x + last-diff last-cc) + + (save-match-data + (save-excursion + (goto-char beg) + (while (re-search-forward regexp end t) + (setq sub-beg (match-beginning 0) + m-b-0 sub-beg + m-e-0 (match-end 0)) + (cond ((match-beginning del-no) ;; del + (put-text-property m-b-0 m-e-0 'face 'egg-diff-del)) + + ((match-beginning add-no) ;; add + (put-text-property m-b-0 m-e-0 'face 'egg-diff-add)) + + ((match-beginning none-no) ;; unchanged + (put-text-property m-b-0 m-e-0 'face 'egg-diff-none)) + + ((match-beginning dst-no) ;; +++ b/file + (setq m-b-x (match-beginning dst-no) + m-e-x (match-end dst-no)) + (put-text-property m-b-0 m-b-x 'face 'egg-diff-add) + (put-text-property m-b-x m-e-x 'face 'egg-diff-none)) + + ((match-beginning src-no) ;; --- a/file + (setq m-b-x (match-beginning src-no) + m-e-x (match-end src-no)) + (put-text-property m-b-0 m-b-x 'face 'egg-diff-del) + (put-text-property m-b-x m-e-x 'face 'egg-diff-none)) + + ((match-beginning conf-beg-no) ;;++<<<<<<< + (setq m-b-x (match-beginning conf-beg-no) + m-e-x (match-end conf-beg-no)) + (put-text-property m-b-0 m-b-x 'face 'egg-diff-conflict) + (put-text-property m-b-x m-e-x 'face 'egg-branch-mono) + (put-text-property m-e-x m-e-0 'face 'egg-diff-none) + ;; mark the whole conflict section + (setq sub-end (egg-safe-search "^++>>>>>>>.+$" end)) + (put-text-property m-b-0 sub-end 'keymap + conflict-map)) + + ((match-beginning conf-end-no) + (setq m-b-x (match-beginning conf-end-no) + m-e-x (match-end conf-end-no)) + ;; just decorate, no mark. + ;; the section was already mark when the conf-beg-no + ;; matched. + (put-text-property m-b-0 m-b-x 'face 'egg-diff-conflict) + (put-text-property m-b-x m-e-x 'face 'egg-branch-mono) + (put-text-property m-e-x m-e-0 'face 'egg-diff-none)) + + ((match-beginning conf-div-no) ;;++======= + ;; just decorate, no mark. + ;; the section was already mark when the conf-beg-no + ;; matched. + (put-text-property m-b-0 m-e-0 'face 'egg-diff-conflict)) + + ((match-beginning hunk-no) ;; hunk @@ + (setq m-b-x (match-beginning hunk-no) + m-e-x (match-end hunk-no) + ;; find the end of the hunk section + sub-end (or (egg-safe-search hunk-end-re end) + end)) + ;; decorate the header + (egg-decorate-hunk-header m-b-x m-e-x m-b-0 m-e-0) + ;; mark the whole hunk based on the last diff header + (egg-delimit-section + :hunk (egg-make-hunk-info + (match-string-no-properties hunk-no) + sub-beg sub-end last-diff) + sub-beg sub-end m-e-0 hunk-map + 'egg-compute-navigation)) + + ((match-beginning cc-hunk-no) ;; cc-hunk + (setq m-b-x (match-beginning cc-hunk-no) + m-e-x (match-end cc-hunk-no) + ;; find the end of the hunk section + sub-end (or (egg-safe-search hunk-end-re end) + end)) + ;; decorate the header + (egg-decorate-hunk-header m-b-x m-e-x m-b-0 m-e-0) + ;; mark the whole hunk based on the last cc-diff header + (egg-delimit-section + :hunk (egg-make-hunk-info + (match-string-no-properties cc-hunk-no) + sub-beg sub-end last-cc) + sub-beg sub-end m-e-0 cc-hunk-map + 'egg-compute-navigation)) + + ((match-beginning diff-no) ;; diff + (setq m-b-x (match-beginning diff-no) + m-e-x (match-end diff-no) + sub-end (or (egg-safe-search diff-end-re end) end) + ;; find the end of the header + head-end (or (egg-safe-search "^@@" end) end)) + ;; decorate the header + (egg-decorate-diff-header m-b-x m-e-x m-b-0 m-e-0) + ;; mark the whole diff + (egg-delimit-section + :diff (setq last-diff + (egg-make-diff-info + (match-string-no-properties diff-no) + sub-beg sub-end head-end)) + sub-beg sub-end m-e-0 diff-map 'egg-compute-navigation)) + + ((match-beginning cc-diff-no) ;; cc-diff + (setq m-b-x (match-beginning cc-diff-no) + m-e-x (match-end cc-diff-no) + sub-end (or (egg-safe-search diff-end-re end) end) + ;; find the end of the header + head-end (or (egg-safe-search "^@@@" end) end)) + ;; decorate the header + (egg-decorate-cc-diff-header m-b-x m-e-x m-b-0 m-e-0) + ;; mark the whole diff + (egg-delimit-section + :diff (setq last-cc + (egg-make-diff-info + (match-string-no-properties cc-diff-no) + sub-beg sub-end head-end)) + sub-beg sub-end m-e-0 cc-diff-map + 'egg-compute-navigation)) + + ((match-beginning index-no) ;; index + (setq m-b-x (match-beginning index-no) + m-e-x (match-end index-no)) + (egg-decorate-diff-index-line m-b-x m-e-x m-b-0 m-b-0)) + ) ;; cond + ) ;; while + ) ;; save-excursion + ) ;;; save -match-data + + nil)) + +(defun egg-decorate-diff-section (&rest args) + "Decorate a section containing a sequence of diffs. +See `egg-decorate-diff-sequence'." + (let ((beg (plist-get args :begin)) + (end (plist-get args :end)) + (a (or (plist-get args :src-prefix) "a/")) + (b (or (plist-get args :dst-prefix) "b/")) + (a-rev (plist-get args :src-revision)) + (b-rev (plist-get args :dst-revision))) + (when (stringp a-rev) + (put-text-property beg end :src-revision a-rev)) + (when (stringp b-rev) + (put-text-property beg end :dst-revision b-rev)) + (egg-decorate-diff-sequence + (nconc (list :src-prefix a :dst-prefix b) args)))) + +(defun egg-diff-section-cmd-visit-file (file) + "Visit file FILE." + (interactive (list (car (get-text-property (point) :diff)))) + (find-file file)) + +(defun egg-diff-section-cmd-visit-file-other-window (file) + "Visit file FILE in other window." + (interactive (list (car (get-text-property (point) :diff)))) + (find-file-other-window file)) + +(defun egg-unmerged-section-cmd-ediff3 (file) + "Run ediff3 to resolve merge conflicts in FILE." + (interactive (list (car (get-text-property (point) :diff)))) + (find-file file) + (egg-resolve-merge-with-ediff)) + +(defun egg-unstaged-section-cmd-ediff (file) + "Compare FILE and its staged copy using ediff." + (interactive (list (car (get-text-property (point) :diff)))) + (find-file file) + (egg-file-do-ediff ":0" "INDEX")) + +(defun egg-staged-section-cmd-ediff3 (file) + "Compare the staged copy of FILE and the version in HEAD using ediff." + (interactive (list (car (get-text-property (point) :diff)))) + (find-file file) + (egg-file-do-ediff ":0" "INDEX" "HEAD")) + +(defvar egg-diff-buffer-info nil) + +(defun egg-diff-section-cmd-ediff (file pos) + "Ediff src and dest versions of FILE based on the diff at POS." + (interactive (list (car (get-text-property (point) :diff)) + (point))) + (let ((commit (get-text-property pos :commit)) + (diff-info egg-diff-buffer-info) + src src-name dst commit) + (find-file file) + (cond (commit + (setq src (egg-describe-rev (concat commit "^")) + dst (egg-describe-rev commit))) + ((setq src (plist-get diff-info :src-revision)) + (setq src (egg-describe-rev src))) + ((setq src (and diff-info ":0")) + (setq src-name "INDEX"))) + (unless src (error "Ooops!")) + (egg-file-do-ediff src src-name dst nil 'ediff2))) + +(defun egg-hunk-compute-line-no (hunk-header hunk-beg) + "Calaculate the effective line number in the original file based +on the position of point in a hunk. HUNK-HEADER is the header and +HUNK-BEG is the starting position of the current hunk." + (let ((limit (line-end-position)) + (line (string-to-number + (nth 2 (save-match-data + (split-string hunk-header "[ @,\+,-]+" t))))) + (adjust 0)) + (save-excursion + (goto-char hunk-beg) + (forward-line 1) + (end-of-line) + (if (< (point) limit) + (while (re-search-forward "^\\(?:\\+\\| \\).*" limit t) + (setq adjust (1+ adjust))))) + (+ line adjust))) + +(defsubst egg-hunk-info-at (pos) + "Rebuild the hunk info at POS. +Hunk info are relative offsets. This function compute the +physical offsets." + (let* ((diff-info (get-text-property pos :diff)) + (head-beg (nth 1 diff-info)) + (hunk-info (get-text-property pos :hunk)) + (hunk-beg (+ (nth 1 hunk-info) head-beg)) + (hunk-end (+ (nth 2 hunk-info) head-beg))) + (list (car diff-info) (car hunk-info) hunk-beg hunk-end))) + +(defun egg-hunk-section-cmd-visit-file (file hunk-header hunk-beg + &rest ignored) + "Visit FILE and goto the current line of the hunk." + (interactive (egg-hunk-info-at (point))) + (let ((line (egg-hunk-compute-line-no hunk-header hunk-beg))) + (find-file file) + (goto-line line))) + +(defun egg-hunk-section-cmd-visit-file-other-window (file hunk-header hunk-beg + &rest ignored) + "Visit FILE in other-window and goto the current line of the hunk." + (interactive (egg-hunk-info-at (point))) + (let ((line (egg-hunk-compute-line-no hunk-header hunk-beg))) + (find-file-other-window file) + (goto-line line))) + +(defun egg-section-cmd-toggle-hide-show (nav) + "Toggle the hidden state of the current navigation section of type NAV." + (interactive (list (get-text-property (point) :navigation))) + + ;; emacs's bug? caused by tooltip + (if (eq buffer-invisibility-spec t) + (setq buffer-invisibility-spec nil)) + + (if (assoc nav buffer-invisibility-spec) + (remove-from-invisibility-spec (cons nav t)) + (add-to-invisibility-spec (cons nav t))) + (force-window-update (current-buffer))) + +(defun egg-section-cmd-toggle-hide-show-children (pos sect-type) + "Toggle the hidden state of the subsections of the current navigation section at POS." + (interactive (list (previous-single-property-change (1+ (point)) + :navigation) + (get-text-property (point) :sect-type))) + (unless pos + (setq pos (point))) + (let ((end (next-single-property-change pos sect-type nil (point-max))) + child-pos child-nav + currently-hidden) + ;; guess the current state + (setq child-pos (next-single-property-change pos :navigation nil end)) + (when child-pos + (setq child-nav (get-text-property child-pos :navigation)) + (setq currently-hidden (and child-nav + (assoc child-nav + buffer-invisibility-spec)))) + (setq child-pos pos) + ;; toggle every child + (while (< (setq child-pos (next-single-property-change child-pos :navigation nil end)) + end) + (setq child-nav (get-text-property child-pos :navigation)) + (if currently-hidden + (remove-from-invisibility-spec (cons child-nav t)) + (add-to-invisibility-spec (cons child-nav t)))) + (force-window-update (current-buffer)))) + +(defun egg-diff-section-patch-string (&optional pos) + "Build a file patch based on the diff section at POS." + (let* ((diff-info (get-text-property (or pos (point)) :diff)) + (beg (nth 1 diff-info)) + (end (+ (nth 2 diff-info) beg))) + (buffer-substring-no-properties beg end))) + +(defun egg-hunk-section-patch-string (&optional pos reverse) + "Build a single hunk patch based on the delta hunk at POS." + (let* ((diff-info (get-text-property (or pos (point)) :diff)) + (head-beg (nth 1 diff-info)) + (head-end (+ (nth 3 diff-info) head-beg)) + (hunk-info (get-text-property (or pos (point)) :hunk)) + (hunk-beg (+ (nth 1 hunk-info) head-beg)) + (hunk-end (+ (nth 2 hunk-info) head-beg))) + ;; craete diff patch + (if (egg-use-region-p) + (egg-hunk-section-patch-region-string pos diff-info reverse) + (concat (buffer-substring-no-properties head-beg head-end) + (buffer-substring-no-properties hunk-beg hunk-end))))) + +(defun egg-use-region-p () + (if (fboundp 'use-region-p) + (use-region-p) + (and transient-mark-mode mark-active))) + +(defun egg-insert-current-line-buffer (buf) + (egg-insert-string-buffer (egg-current-line-string) buf)) + +(defun egg-current-line-string () + (buffer-substring-no-properties + (line-beginning-position) (line-beginning-position 2))) + +(defun egg-insert-string-buffer (string buf) + (with-current-buffer buf + (insert string))) + +(defun egg-hunk-section-patch-region-string (pos diff-info reverse) + (let* ((head-beg (nth 1 diff-info)) + (head-end (+ (nth 3 diff-info) head-beg)) + (hunk-info (get-text-property (or pos (point)) :hunk)) + (hunk-beg (+ (nth 1 hunk-info) head-beg)) + (hunk-end (+ (nth 2 hunk-info) head-beg)) + (beg (region-beginning)) + (end (region-end)) + (hunk-buf (current-buffer))) + (with-temp-buffer + (let ((buf (current-buffer))) + (with-current-buffer hunk-buf + ;; insert header + (egg-insert-string-buffer + (buffer-substring-no-properties head-beg head-end) buf) + (goto-char hunk-beg) + ;; insert beginning of hunk + (egg-insert-current-line-buffer buf) + (forward-line) + (let ((copy-op (if reverse "+" "-"))) + (while (< (point) hunk-end) + (if (and (<= beg (point)) (< (point) end)) + (egg-insert-current-line-buffer buf) + (cond ((looking-at " ") + (egg-insert-current-line-buffer buf)) + ((looking-at copy-op) + (egg-insert-string-buffer + (concat + " " + (buffer-substring-no-properties + (+ (point) 1) (line-beginning-position 2))) buf)))) + (forward-line)))) + ;; with current buffer `buf' + (diff-fixup-modifs (point-min) (point-max)) + (buffer-string))))) + +;;;======================================================== +;;; Buffer +;;;======================================================== +(defvar egg-buffer-refresh-func nil) +(defvar egg-buffer-async-cmd-refresh-func nil) +(defvar egg-internal-update-index-timer nil) + +(defsubst egg-buffer-async-do (accepted-code &rest args) + "Run git asynchronously and refresh the current buffer on exit. +exit code ACCEPTED-CODE is considered a success." + (egg-async-do accepted-code + (cons (or egg-buffer-async-cmd-refresh-func + egg-buffer-refresh-func) + (list (current-buffer))) + args)) + +(defsubst egg-run-buffers-update-hook (&optional newly-read-state) + "Update all egg special buffers." + (let ((egg-internal-current-state + (or newly-read-state (egg-get-repo-state)))) + (run-hooks 'egg-buffers-refresh-hook))) + +(defun egg-buffer-cmd-refresh () + "Refresh the current egg special buffer." + (interactive) + (when (and (egg-git-dir) + (functionp egg-buffer-refresh-func)) + (funcall egg-buffer-refresh-func (current-buffer)) + (recenter))) + +(defun egg-buffer-cmd-next-block (nav-prop) + "Move to the next block indentified by text property NAV-PROP." + (goto-char (or (next-single-property-change (point) nav-prop) + (point)))) + +(defun egg-buffer-cmd-prev-block (nav-prop) + "Move to the previous block indentified by text property NAV-PROP." + (goto-char (previous-single-property-change (point) nav-prop + nil (point-min)))) + +(defun egg-buffer-cmd-navigate-next () + "Move to the next section." + (interactive) + (egg-buffer-cmd-next-block :navigation)) + +(defun egg-buffer-cmd-navigate-prev () + "Move to the previous section." + (interactive) + (egg-buffer-cmd-prev-block :navigation)) + +(defconst egg-buffer-mode-map + (let ((map (make-sparse-keymap "Egg:Buffer"))) + (define-key map (kbd "q") 'egg-quit-buffer) + (define-key map (kbd "g") 'egg-buffer-cmd-refresh) + (define-key map (kbd "n") 'egg-buffer-cmd-navigate-next) + (define-key map (kbd "p") 'egg-buffer-cmd-navigate-prev) + map) + "Common map for an egg special buffer.\\{egg-buffer-mode-map}" ) + +(defun egg-get-buffer (fmt create) + "Get a special egg buffer. If buffer doesn't exist and CREATE was not nil then +creat the buffer. FMT is used to construct the buffer name. The name is built as: +(format FMT current-dir-name git-dir-full-path)." + (let* ((git-dir (egg-git-dir)) + (dir (file-name-directory git-dir)) + (dir-name (file-name-nondirectory + (directory-file-name dir))) + (buf-name (format fmt dir-name git-dir)) + (default-directory dir) + (buf (get-buffer buf-name))) + (unless (or (bufferp buf) (not create)) + (setq buf (get-buffer-create buf-name))) + buf)) + +(defvar egg-orig-window-config nil) + +(defun egg-quit-buffer (&optional win) + "Leave (and burry) an egg special buffer" + (interactive) + (let ((orig-win-cfg egg-orig-window-config) + (mode major-mode)) + (quit-window (memq 'kill (cdr (assq mode egg-quit-window-actions))) win) + (if (and orig-win-cfg + (window-configuration-p orig-win-cfg) + (memq 'restore-windows (cdr (assq mode egg-quit-window-actions)))) + (set-window-configuration orig-win-cfg)))) + +(defmacro define-egg-buffer (type name-fmt &rest body) + "Define an egg-special-file type." + (let* ((type-name (symbol-name type)) + (get-buffer-sym (intern (concat "egg-get-" type-name "-buffer"))) + (buffer-mode-sym (intern (concat "egg-" type-name "-buffer-mode"))) + (buffer-mode-hook-sym (intern (concat "egg-" type-name "-buffer-mode-hook"))) + (buffer-mode-map-sym (intern (concat "egg-" type-name "-buffer-mode-map"))) + (update-buffer-no-create-sym (intern (concat "egg-update-" type-name "-buffer-no-create")))) + `(progn + (defun ,buffer-mode-sym () + ,@body + (set (make-local-variable 'egg-orig-window-config) + (current-window-configuration)) + ;; (message "buffer %s win-cfg %s" (buffer-name) egg-orig-window-config) + (set (make-local-variable 'egg-internal-buffer-obarray) + (make-vector 67 0))) + + (defun ,get-buffer-sym (&optional create) + (let ((buf (egg-get-buffer ,name-fmt create))) + (when (bufferp buf) + (with-current-buffer buf + (unless (eq major-mode ',buffer-mode-sym) + (,buffer-mode-sym)))) + buf)) + ,(unless (string-match ":" type-name) + `(progn + (defun ,update-buffer-no-create-sym () + (let ((buf (,get-buffer-sym))) + (when (bufferp buf) + (with-current-buffer buf + (when (functionp egg-buffer-refresh-func) + (funcall egg-buffer-refresh-func buf)))))) + (add-hook 'egg-buffers-refresh-hook ',update-buffer-no-create-sym)))))) + + +;; (cl-macroexpand '(define-egg-buffer diff "*diff-%s@egg:%s*")) +;; (cl-macroexpand ' (define-egg-buffer diff (buf) "*diff-%s@egg:%s*" (show-diff buf) )) + + + +;;;======================================================== +;;; Status Buffer +;;;======================================================== +(defconst egg-status-buffer-mode-map + (let ((map (make-sparse-keymap "Egg:StatusBuffer"))) + (set-keymap-parent map egg-buffer-mode-map) + (define-key map (kbd "c") 'egg-commit-log-edit) + (define-key map (kbd "o") 'egg-checkout-ref) + (define-key map (kbd "l") 'egg-log) + (define-key map (kbd "w") 'egg-buffer-stash-wip) + (define-key map (kbd "L") 'egg-reflog) + (define-key map (kbd "S") 'egg-stage-all-files) + (define-key map (kbd "d") 'egg-diff-ref) + map) + "Keymap for the status buffer.\\{egg-status-buffer-mode-map}") + +(defconst egg-status-buffer-rebase-map + (let ((map (make-sparse-keymap "Egg:StatusBufferRebase"))) + (set-keymap-parent map egg-section-map) + (define-key map (kbd "x") 'egg-buffer-rebase-abort) + (define-key map (kbd "u") 'egg-buffer-selective-rebase-skip) + (define-key map (kbd "RET") 'egg-buffer-selective-rebase-continue) + map) + "Context keymap for the repo section of the status buffer when + rebase is in progress.\\{egg-status-buffer-rebase-map}") + +(defun egg-buffer-do-rebase (upstream-or-action + &optional old-base prompt) + "Perform rebase action from an egg special buffer. +See `egg-do-rebase-head'." + (let ((git-dir (egg-git-dir)) + modified-files res) + (if (stringp upstream-or-action) + (unless (egg-repo-clean) + (egg-status) + (error "Repo %s is not clean" git-dir)) + (unless (file-directory-p (concat git-dir "/" egg-git-rebase-subdir)) + (error "No rebase in progress in directory %s" + (file-name-directory git-dir)))) + (setq res (egg-do-rebase-head upstream-or-action old-base prompt)) + (setq modified-files (plist-get res :files)) + (if modified-files + (egg-revert-visited-files modified-files)) + (message "GIT-REBASE> %s" (plist-get res :message)) + (plist-get res :success))) + +(defun egg-buffer-rebase-continue () + "Continue the current rebase session." + (interactive) + (message "continue with current rebase") + (unless (egg-buffer-do-rebase :continue) + (egg-status))) + +(defsubst egg-do-async-rebase-continue (callback closure &optional + action + exit-code) + "Continue the current rebase session asynchronously." + (let ((process-environment process-environment) + (action (or action "--continue")) + (buffer (current-buffer)) + proc) + (setenv "EDITOR" "\nplease commit in egg") + (setq proc (egg-async-1 (list callback closure) "rebase" action)) + (process-put proc :orig-buffer buffer) + proc)) + +(defun egg-buffer-selective-rebase-action (action) + "Perform ACTION to continue the current rebase session. +The mode, sync or async, will depend on the nature of the current +rebase session." + (if (not (egg-interactive-rebase-in-progress)) + (unless (egg-buffer-do-rebase action) + (egg-status)) + (setq action (cdr (assq action '((:skip . "--skip") + (:continue . "--continue") + (:abort . "--abort"))))) + (egg-do-async-rebase-continue + #'egg-handle-rebase-interactive-exit + (egg-pick-file-contents (concat (egg-git-rebase-dir) "head") "^.+$") + action))) + +(defun egg-buffer-selective-rebase-continue () + "Continue the current rebase session. +The mode, sync or async, will depend on the nature of the current +rebase session." + (interactive) + (message "continue with current rebase") + (egg-buffer-selective-rebase-action :continue)) + +(defun egg-buffer-selective-rebase-skip () + "Skip the current commit and continue the current rebase session. +The mode, sync or async, will depend on the nature of the current +rebase session." + (interactive) + (message "skip rebase's current commit") + (egg-buffer-selective-rebase-action :skip)) + +(defun egg-buffer-rebase-skip () + (interactive) + (message "skip rebase's current commit") + (unless (egg-buffer-do-rebase :skip) + (egg-status))) + +(defun egg-buffer-rebase-abort () + (interactive) + (message "abort current rebase") + (egg-buffer-do-rebase :abort) + (egg-status)) + +(defun egg-rebase-in-progress () + (plist-get (egg-repo-state) :rebase-step)) + +(defsubst egg-pretty-help-text (&rest strings) + "Perform key bindings substitutions and highlighting in STRINGS." + (let* ((map (current-local-map)) last-found) + (with-temp-buffer + (use-local-map map) + (save-match-data + ;; key substitutions + (insert (substitute-command-keys + (mapconcat 'identity strings ""))) + (goto-char (point-min)) + ;; key highlighting + (while (re-search-forward "\\(\\<[^\n \t:]+\\|[/+.~*=-]\\):" nil t) + (put-text-property (match-beginning 1) (match-end 1)'face 'egg-help-key) + (if last-found + (put-text-property last-found (1- (match-beginning 0)) + 'face 'egg-text-help)) + (setq last-found (point))) + (if last-found + (put-text-property last-found (line-end-position) 'face 'egg-text-help)) + ;; return the total + (buffer-string))))) + +(defconst egg-status-buffer-common-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) + (egg-pretty-help-text + "\\\n" + "\\[egg-buffer-cmd-navigate-prev]:previous block " + "\\[egg-buffer-cmd-navigate-next]:next block " + "\\[egg-commit-log-edit]:commit staged modifications " + "\\[egg-log]:show repo's history\n" + "\\[egg-stage-all-files]:stage all modifications " + "\\[egg-diff-ref]:diff other repos " + "\\" + "\\[egg-section-cmd-toggle-hide-show]:hide/show block " + "\\[egg-section-cmd-toggle-hide-show-children]:hide sub-blocks \n" + "\\" + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n"))) + +(defconst egg-status-buffer-rebase-help-text + (concat + (egg-text "Key Bindings for Rebase Operations:" 'egg-help-header-2) + (egg-pretty-help-text + "\\\n" + "\\[egg-buffer-selective-rebase-continue]:resume rebase " + "\\[egg-buffer-selective-rebase-skip]:skip this rebase step " + "\\[egg-buffer-rebase-abort]:abort current rebase session\n"))) + +(defconst egg-status-buffer-diff-help-text + (concat + (egg-text "Extra Key Bindings for the Diff Sections:" + 'egg-help-header-2) + (egg-pretty-help-text + "\\\n" + "\\[egg-diff-section-cmd-visit-file-other-window]:visit file/line " + "\\[egg-diff-section-cmd-stage]:stage/unstage file/hunk/selected area " + "\\[egg-diff-section-cmd-undo]:undo file/hunk's modifications\n"))) + +(defun egg-sb-insert-repo-section () + "Insert the repo section into the status buffer." + (let* ((state (egg-repo-state)) + (sha1 (plist-get state :sha1)) + (beg (point)) + (map egg-section-map) + (rebase-step (plist-get state :rebase-step)) + (rebase-num (plist-get state :rebase-num)) + inv-beg help-beg help-inv-beg rebase-beg) + + (unless (and sha1 state) + (error "Invalid repo state: sha1 = %s, state = %S" + sha1 state)) + + ;; head, sha1 and git-dir + (insert (egg-text (egg-pretty-head-string state) 'egg-branch) "\n" + (egg-text sha1 'font-lock-string-face) "\n" + (egg-text (plist-get state :gitdir) 'font-lock-constant-face) + "\n") + ;; invisibility start at the newline + (setq inv-beg (1- (point))) + (when rebase-step + ;; Rebase info and keybindings + (insert (format "Rebase: commit %s of %s\n" rebase-step rebase-num)) + (setq map egg-status-buffer-rebase-map)) + (when (memq :status egg-show-key-help-in-buffers) + ;; Help + (insert "\n") + (setq help-beg (point)) + (insert (egg-text "Help" 'egg-help-header-1) "\n") + (put-text-property help-beg (point) 'help-echo (egg-tooltip-func)) + (setq help-inv-beg (1- (point))) + (insert egg-status-buffer-common-help-text) + (when (eq egg-status-buffer-rebase-map map) + (insert egg-status-buffer-rebase-help-text)) + (insert egg-status-buffer-diff-help-text)) + ;; Mark the repo section + (egg-delimit-section :section 'repo beg (point) inv-beg map 'repo) + (when help-beg + ;; Mark the help sub-section so it can be hidden + (egg-delimit-section :help 'help help-beg (point) help-inv-beg map + 'egg-compute-navigation)) + (put-text-property beg (or help-beg (point)) + 'help-echo (egg-tooltip-func)))) + +(defun egg-ignore-pattern-from-string-at-point () + (interactive) + (let ((string (egg-string-at-point)) + (file (ffap-file-at-point)) + dir pattern gitignore) + (setq pattern (read-string "ignore pattern: " + (if (string-match "\\.[^.]+\\'" string) + (match-string-no-properties 0 string) + string))) + (when (equal pattern "") + (error "Can't ignore empty string!")) + (setq dir (if (stringp file) + (file-name-directory (expand-file-name file)) + default-directory)) + (setq gitignore + (read-file-name (format "add pattern `%s' to: " pattern) + dir nil nil ".gitignore")) + (save-excursion + (with-current-buffer (find-file-noselect gitignore t t) + (goto-char (point-max)) + (insert pattern "\n") + (save-buffer) + (kill-buffer (current-buffer)))) + (egg-buffer-cmd-refresh))) + +(defun egg-status-buffer-stage-untracked-file () + (interactive) + (let ((file (ffap-file-at-point))) + (when (egg-sync-do-file file egg-git-command nil nil + (list "add" "--" file)) + (message "new file %s added" file)))) + +(defconst egg-untracked-file-map + (let ((map (make-sparse-keymap "Egg:UntrackedFile"))) + (define-key map (kbd "RET") 'egg-find-file-at-point) + (define-key map (kbd "DEL") 'egg-ignore-pattern-from-string-at-point) + (define-key map "s" 'egg-status-buffer-stage-untracked-file) + (define-key map "i" 'egg-status-buffer-stage-untracked-file) + map)) + +(defun egg-sb-insert-untracked-section () + "Insert the untracked files section into the status buffer." + (let ((beg (point)) inv-beg end) + (insert (egg-prepend "Untracked Files:" "\n\n" + 'face 'egg-section-title + 'help-echo (egg-tooltip-func)) + "\n") + (setq inv-beg (1- (point))) + (call-process egg-git-command nil t nil "ls-files" "--others" + "--exclude-standard") + (setq end (point)) + (egg-delimit-section :section 'untracked beg end + inv-beg egg-section-map 'untracked) + (put-text-property inv-beg end 'keymap egg-untracked-file-map) + (put-text-property (1+ inv-beg) end 'help-echo (egg-tooltip-func)))) + +(defun egg-sb-insert-unstaged-section (title &rest extra-diff-options) + "Insert the unstaged changes section into the status buffer." + (let ((beg (point)) inv-beg diff-beg) + (insert (egg-prepend title "\n\n" 'face 'egg-section-title + 'help-echo (egg-tooltip-func)) + "\n") + (setq diff-beg (point)) + (setq inv-beg (1- (point))) + (apply 'call-process egg-git-command nil t nil "diff" "--no-color" + "-M" "-p" "--src-prefix=INDEX:/" "--dst-prefix=WORKDIR:/" + extra-diff-options) + (egg-delimit-section :section 'unstaged beg (point) + inv-beg egg-section-map 'unstaged) + ;; this section might contains merge conflicts, thus cc-diff + (egg-decorate-diff-section :begin diff-beg + :end (point) + :src-prefix "INDEX:/" + :dst-prefix "WORKDIR:/" + :diff-map egg-unstaged-diff-section-map + :hunk-map egg-unstaged-hunk-section-map + :cc-diff-map egg-unmerged-diff-section-map + :cc-hunk-map egg-unmerged-hunk-section-map + :conflict-map egg-unmerged-hunk-section-map + ))) + +(defun egg-sb-insert-staged-section (title &rest extra-diff-options) + "Insert the staged changes section into the status buffer." + (let ((beg (point)) inv-beg diff-beg) + (insert (egg-prepend title "\n\n" + 'face 'egg-section-title + 'help-echo (egg-tooltip-func)) + "\n") + (setq diff-beg (point) + inv-beg (1- diff-beg)) + (apply 'call-process egg-git-command nil t nil "diff" "--no-color" + "--cached" "-M" "-p" "--src-prefix=HEAD:/" "--dst-prefix=INDEX:/" + extra-diff-options) + (egg-delimit-section :section 'staged beg (point) + inv-beg egg-section-map 'staged) + ;; this section never contains merge conflicts, thus no cc-diff + (egg-decorate-diff-section :begin diff-beg + :end (point) + :src-prefix "HEAD:/" + :dst-prefix "INDEX:/" + :diff-map egg-staged-diff-section-map + :hunk-map egg-staged-hunk-section-map))) + +(defun egg-checkout-ref (&optional default) + "Prompt a revision to checkout. Default is DEFAULT." + (interactive (list (car (get-text-property (point) :ref)))) + (egg-do-checkout (completing-read "checkout: " (egg-all-refs) + nil nil (or default "HEAD")))) + +(defsubst egg-buffer-show-all () + (interactive) + (setq buffer-invisibility-spec nil) + (if (interactive-p) + (force-window-update (current-buffer)))) + +(defsubst egg-buffer-hide-all () + "Hide all sections in current special egg buffer." + (interactive) + (let ((pos (point-min)) nav) + (while (setq pos (next-single-property-change (1+ pos) :navigation)) + (setq nav (get-text-property pos :navigation)) + (add-to-invisibility-spec (cons nav t)))) + (if (interactive-p) + (force-window-update (current-buffer)))) + +(defsubst egg-buffer-hide-section-type (sect-type) + "Hide sections of SECT-TYPE in current special egg buffer." + (let ((pos (point-min)) nav) + (while (setq pos (next-single-property-change (1+ pos) sect-type)) + (when (get-text-property pos sect-type) + (setq nav (get-text-property pos :navigation)) + (add-to-invisibility-spec (cons nav t)))))) + +(defsubst egg-buffer-maybe-hide-all () + "If requsted, hide all sections in current special egg buffer. +See `egg-buffer-hide-sub-blocks-on-start'." + (let ((sect-type (cdr (assq major-mode + egg-buffer-hide-section-type-on-start)))) + (cond ((memq major-mode egg-buffer-hide-sub-blocks-on-start) + (egg-buffer-hide-all)) + ((and sect-type (symbolp sect-type)) + (egg-buffer-hide-section-type sect-type))))) + +(defsubst egg-buffer-maybe-hide-help (help-nav &optional top-nav) + "If requested, hide the help section in the current special buffer. +See `egg-buffer-hide-help-on-start'." + (if (memq major-mode egg-buffer-hide-help-on-start) + (add-to-invisibility-spec + (cons (if (symbolp help-nav) help-nav + (egg-make-navigation top-nav help-nav)) + t)))) + +(defun egg-status-buffer-redisplay (buf &optional init) + "(Re)Display the contents of the status buffer in BUF. +If INIT was not nil, then perform 1st-time initializations as well." + (with-current-buffer buf + (let ((inhibit-read-only t) + (orig-pos (point))) + (erase-buffer) + + (dolist (sect egg-status-buffer-sections) + (cond ((eq sect 'repo) (egg-sb-insert-repo-section)) + ((eq sect 'unstaged) (egg-sb-insert-unstaged-section "Unstaged Changes:")) + ((eq sect 'staged) (egg-sb-insert-staged-section "Staged Changes:")) + ((eq sect 'untracked) (egg-sb-insert-untracked-section)))) + (if init (egg-buffer-maybe-hide-all)) + (if init (egg-buffer-maybe-hide-help "help" 'repo)) + (goto-char orig-pos)))) + +(defun egg-internal-background (proc msg) + "Background job sentinel." + (let ((name (process-name proc))) + (cond ((string= msg "finished\n") + (message "EGG BACKGROUND: %s finished." name)) + ((string= msg "killed\n") + (message "EGG BACKGROUND: %s was killed." name)) + ((string-match "exited abnormally" msg) + (message "EGG BACKGROUND: %s failed." name)) + (t (message "EGG BACKGROUND: %s is weird!" name))))) + +(defun egg-internal-background-refresh-index (buffer-name) + (let ((buffer (get-buffer buffer-name)) + proc) + (when (and buffer (buffer-live-p buffer)) + (with-current-buffer buffer + (setq proc (start-process (format "refresh index in %s" + default-directory) + nil + egg-git-command "update-index" + "-q" "--really-refresh" "--unmerged")) + (set-process-sentinel proc #'egg-internal-background))))) + +(defvar egg-internal-status-buffer-names-list nil) +(defvar egg-internal-background-jobs-timer nil) + +(defun egg-status-buffer-background-job () + (when egg-refresh-index-in-backround + (mapcar #'egg-internal-background-refresh-index + egg-internal-status-buffer-names-list))) + +(defsubst egg-internal-background-jobs-restart () + (cancel-function-timers #'egg-status-buffer-background-job) + (setq egg-internal-background-jobs-timer + (run-with-idle-timer egg-background-idle-period t + #'egg-status-buffer-background-job))) + +(defun egg-set-background-idle-period (var val) + (custom-set-default var val) + (egg-internal-background-jobs-restart)) + +(defcustom egg-background-idle-period 30 + "How long emacs has been idle before we trigger background jobs." + :group 'egg + :set 'egg-set-background-idle-period + :type 'integer) + +(egg-internal-background-jobs-restart) + +(define-egg-buffer status "*%s-status@%s*" + "Major mode to display the egg status buffer." + (kill-all-local-variables) + (setq buffer-read-only t) + (setq major-mode 'egg-status-buffer-mode + mode-name "Egg-Status" + mode-line-process "" + truncate-lines t) + (use-local-map egg-status-buffer-mode-map) + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-status-buffer-redisplay) + (setq buffer-invisibility-spec nil) + (add-to-list 'egg-internal-status-buffer-names-list (buffer-name)) + (run-mode-hooks 'egg-status-buffer-mode-hook)) + + +;;; I'm here +(defun egg-status-make-section-menu (&optional name) + (let ((map (make-sparse-keymap name))) + (define-key map [f-stage] (list 'menu-item "Stage File" + 'egg-diff-section-cmd-stage + :visible '(egg-diff-at-point) + :enable '(egg-point-in-section 'unstaged))) + + (define-key map [f-unstage] (list 'menu-item "Unstage File" + 'egg-diff-section-cmd-unstage + :visible '(egg-diff-at-point) + :enable '(egg-point-in-section 'staged))) + + (define-key map [f-undo] (list 'menu-item "Undo File's Modifications" + 'egg-diff-section-cmd-undo + :visible '(egg-diff-at-point) + :enable '(egg-point-in-section 'unstaged))) + + (define-key map [h-stage] (list 'menu-item "Stage Hunk" + 'egg-hunk-section-cmd-stage + :visible '(egg-hunk-at-point) + :enable '(egg-point-in-section 'unstaged))) + + (define-key map [h-unstage] (list 'menu-item "Unstage Hunk" + 'egg-hunk-section-cmd-unstage + :visible '(egg-hunk-at-point) + :enable '(egg-point-in-section 'staged))) + + (define-key map [h-undo] (list 'menu-item "Undo Hunk" + 'egg-hunk-section-cmd-undo + :visible '(egg-hunk-at-point) + :enable '(egg-point-in-section 'unstaged))) + + (define-key map [sp9] '("--")) + (define-key map [prev] (list 'menu-item "Goto Prev Block" + 'egg-buffer-cmd-navigate-prev + :enable '(egg-navigation-at-point))) + (define-key map [next] (list 'menu-item "Goto Next Block" + 'egg-buffer-cmd-navigate-next + :enable '(egg-navigation-at-point))) + (define-key map [hs] (list 'menu-item "Hide/Show Current Block" + 'egg-section-cmd-toggle-hide-show + :enable '(egg-navigation-at-point))) + (define-key map [hs-sub] (list 'menu-item "Hide/Show SubBlocks" + 'egg-section-cmd-toggle-hide-show-children + :enable '(egg-navigation-at-point))) + (define-key map [sp8] '("--")) + (define-key map [goto-file] (list 'menu-item "Open File" + 'egg-diff-section-cmd-visit-file-other-window + :visble '(and (egg-diff-at-point) (not (egg-hunk-at-point))))) + (define-key map [goto-line] (list 'menu-item "Locate Line" + 'egg-hunk-section-cmd-visit-file-other-window + :visible '(egg-hunk-at-point))) + (define-key map [ediff] (list 'menu-item "Ediff: WorkDir vs INDEX" + 'egg-unstaged-section-cmd-ediff + :visible '(egg-diff-at-point) + :enable '(egg-point-in-section 'unstaged))) + (define-key map [ediff3] (list 'menu-item "Ediff3: WorkDir vs INDEX vs HEAD" + 'egg-staged-section-cmd-ediff3 + :visible '(egg-diff-at-point) + :enable '(egg-point-in-section 'staged))) + map)) + +(defconst egg-status-buffer-unstaged-diff-menu (egg-status-make-section-menu "Unstaged Delta")) +(defconst egg-status-buffer-unstaged-hunk-menu (egg-status-make-section-menu "Unstaged Hunk")) +(defconst egg-status-buffer-staged-diff-menu (egg-status-make-section-menu "Staged Delta")) +(defconst egg-status-buffer-staged-hunk-menu (egg-status-make-section-menu "Staged Hunk")) +(defconst egg-status-buffer-mode-delta-menu (egg-status-make-section-menu)) + +(defun egg-status-popup-delta-menu (event menu) + (let* ((keys (progn + (force-mode-line-update) + (x-popup-menu event menu))) + (cmd (and keys (lookup-key menu (apply 'vector keys))))) + (when (and cmd (commandp cmd)) + (call-interactively cmd)))) + +(defun egg-status-popup-unstaged-diff-menu (event) + (interactive "e") + (egg-status-popup-delta-menu event egg-status-buffer-unstaged-diff-menu)) + +(defun egg-status-popup-staged-diff-menu (event) + (interactive "e") + (egg-status-popup-delta-menu event egg-status-buffer-staged-diff-menu)) + +(defun egg-status-popup-unstaged-hunk-menu (event) + (interactive "e") + (egg-status-popup-delta-menu event egg-status-buffer-unstaged-hunk-menu)) + +(defun egg-status-popup-staged-hunk-menu (event) + (interactive "e") + (egg-status-popup-delta-menu event egg-status-buffer-staged-hunk-menu)) + + +(defconst egg-status-buffer-menu (make-sparse-keymap "Egg (Git)")) + +(define-key egg-status-buffer-mode-map + [menu-bar egg-status-buffer-mode] (cons "Egg (Git)" egg-status-buffer-menu)) + +(let ((menu egg-status-buffer-menu)) + (define-key menu [quit] '(menu-item "Close Status View" egg-quit-buffer)) + (define-key menu [refresh] '(menu-item "Refresh Status View" egg-buffer-cmd-refresh)) + (define-key menu [log] '(menu-item "Show Branch History" egg-log)) + (define-key menu [sp3] '("--")) + (define-key menu [rb-skip] '(menu-item "Skip Rebase Session's Current Commit" + egg-buffer-selective-rebase-skip + :enable (egg-rebase-in-progress))) + (define-key menu [rb-abort] '(menu-item "Abort Rebase Session" + egg-buffer-rebase-abort + :enable (egg-rebase-in-progress))) + (define-key menu [rb-cont] '(menu-item "Resume Rebase Session" + egg-buffer-selective-rebase-continue + :enable (egg-rebase-in-progress))) + (define-key menu [sp2] '("--")) + (define-key menu [delta] (list 'menu-item "Delta" + egg-status-buffer-mode-delta-menu + :enable '(egg-diff-at-point))) + (define-key menu [commit] '(menu-item "Commit Staged Changes" + egg-commit-log-edit)) + (define-key menu [stage] '(menu-item "Stage All Modifications" + egg-stage-all-files)) + (define-key menu [stage-untracked] '(menu-item "Stage All Untracked Files" + egg-stage-untracked-files)) + (define-key menu [sp1] '("--")) + (define-key menu [hide-all] '(menu-item "Hide All" egg-buffer-hide-all)) + (define-key menu [show-all] '(menu-item "Show All" egg-buffer-show-all)) + (define-key menu [hs] '(menu-item "Hide/Show Block" + egg-section-cmd-toggle-hide-show + :enable (egg-navigation-at-point))) + (define-key menu [hs-sub] '(menu-item "Hide/Show SubBlocks" + egg-section-cmd-toggle-hide-show-children + :enable (egg-navigation-at-point))) + (define-key menu [prev] '(menu-item "Goto Previous Block" egg-buffer-cmd-navigate-prev + :enable (egg-navigation-at-point))) + (define-key menu [next] '(menu-item "Goto Next Block" egg-buffer-cmd-navigate-next + :enable (egg-navigation-at-point)))) + +(defvar egg-switch-to-buffer nil "Set to nonnil for egg-status to switch to the status buffer in the same window.") + +(defun egg-status (&optional select caller) + (interactive "P") + (let* ((egg-internal-current-state + (egg-repo-state (if (interactive-p) :error-if-not-git))) + (buf (egg-get-status-buffer 'create))) + (with-current-buffer buf + (egg-status-buffer-redisplay buf 'init)) + (cond ((eq caller :sentinel) (pop-to-buffer buf)) + (select (pop-to-buffer buf t)) + (egg-switch-to-buffer (switch-to-buffer buf)) + ((interactive-p) (display-buffer buf t)) + (t (pop-to-buffer buf t))))) + +;;;======================================================== +;;; action +;;;======================================================== + +(defun egg-revert-visited-files (file-or-files) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir)) + (files (if (consp file-or-files) + file-or-files + (list file-or-files)))) + (mapcar (lambda (file) + (let ((buf (get-file-buffer file))) + (when (bufferp buf) + (with-current-buffer buf + (when (equal (egg-git-dir) git-dir) + (revert-buffer t t t)))))) + files))) + +(defun egg-revert-all-visited-files () + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir)) + bufs files) + (setq files + (delq nil (mapcar (lambda (buf) + (with-current-buffer buf + (when (and (buffer-file-name buf) + (equal (egg-git-dir) git-dir)) + (buffer-file-name buf)))) + (buffer-list)))) + (when (consp files) + (setq files (mapcar 'expand-file-name + (apply 'egg-git-to-lines "ls-files" files))) + (when (consp files) + (egg-revert-visited-files files))))) + +(defun egg-cmd-log-buffer () + (or (get-buffer (concat " *egg-cmd-logs@" (egg-git-dir) "*")) + (let ((git-dir (egg-git-dir)) + (default-directory default-directory) + dir) + (unless git-dir + (error "Can't find git dir in %s" default-directory)) + (setq dir (file-name-nondirectory git-dir)) + (setq default-directory dir) + (get-buffer-create (concat " *egg-cmd-logs@" git-dir "*"))))) + +(defsubst egg-cmd-log (&rest strings) + (with-current-buffer (egg-cmd-log-buffer) + (goto-char (point-max)) + (cons (current-buffer) + (prog1 (point) + (apply 'insert "LOG/" strings))))) + +(defun egg-sync-handle-exit-code (ret accepted-codes logger) + (let (output) + (with-current-buffer (car logger) + (save-excursion + (goto-char (cdr logger)) + (forward-line 1) + (setq output (buffer-substring-no-properties + (point) (point-max))))) + (egg-cmd-log (format "RET:%d\n" ret)) + (if (listp accepted-codes) + (setq accepted-codes (cons 0 accepted-codes)) + (setq accepted-codes (list 0 accepted-codes))) + (if (null (memq ret accepted-codes)) + (with-current-buffer (car logger) + (widen) + (narrow-to-region (cdr logger) (point-max)) + (display-buffer (current-buffer) t) + nil) + (egg-run-buffers-update-hook) + output))) + +(defun egg-sync-do (program stdin accepted-codes args) + (let (logger ret) + (setq logger (egg-cmd-log "RUN:" program " " + (mapconcat 'identity args " ") + (if stdin " (length output) 1)) + (when (numberp line-no) + (when (setq output (save-match-data (split-string output "\n" t))) + (cond ((< line-no 0) + (setq line-no (1+ line-no)) + (setq output (nth line-no (nreverse output)))) + ((> line-no 0) + (setq line-no (1- line-no)) + (setq output (nth line-no output))) + (t (setq output nil))))) + (when (stringp output) + (message "%s> %s" prefix output) + t))) + +(defun egg-hunk-section-cmd-stage (pos) + (interactive (list (point))) + (egg-show-git-output + (egg-hunk-section-patch-cmd pos egg-git-command "apply" "--cached") + -1 "GIT-APPLY")) + +(defun egg-hunk-section-cmd-unstage (pos) + (interactive (list (point))) + (egg-show-git-output + (egg-hunk-section-patch-cmd pos egg-git-command "apply" + "--cached" "--reverse") + -1 "GIT-APPLY")) + +(defun egg-hunk-section-cmd-undo (pos) + (interactive (list (point))) + (unless (or (not egg-confirm-undo) + (y-or-n-p "irreversibly remove the hunk under cursor? ")) + (error "Too chicken to proceed with undo operation!")) + (let ((file (egg-hunk-section-patch-cmd pos egg-patch-command + "-p1" "--quiet" "--reverse"))) + (if (consp file) (setq file (car file))) + (when (stringp file) + (egg-revert-visited-files file)))) + +(defun egg-diff-section-patch-cmd (pos accepted-codes &rest args) + (let ((file (car (get-text-property pos :diff)))) + (unless (stringp file) + (error "No diff with file-name here!")) + (egg-sync-do-file file egg-git-command nil accepted-codes + (append args (list file))))) + +(defun egg-diff-section-cmd-stage (pos) + (interactive (list (point))) + (let ((file (car (get-text-property pos :diff)))) + (egg-diff-section-patch-cmd pos nil + (if (file-exists-p file) + "add" + "rm")))) + +(defun egg-diff-section-cmd-unstage (pos) + (interactive (list (point))) + (egg-show-git-output + (egg-diff-section-patch-cmd pos 1 "reset" "HEAD" "--") + 1 "GIT-RESET")) + +(defun egg-diff-section-cmd-undo-old-no-revsion-check (pos) + (interactive (list (point))) + (let ((file (egg-diff-section-patch-cmd pos nil "checkout" "--"))) + (if (consp file) (setq file (car file))) + (when (stringp file) + (egg-revert-visited-files file)))) + +(defun egg-diff-section-cmd-undo (pos) + (interactive (list (point))) + (unless (or (not egg-confirm-undo) + (y-or-n-p "irreversibly remove the delta under cursor? ")) + (error "Too chicken to proceed with undo operation!")) + + (let ((file (car (or (get-text-property pos :diff) + (error "No diff with file-name here!")))) + (src-rev (get-text-property pos :src-revision)) + args) + (setq args + (if (stringp src-rev) + (list "checkout" src-rev "--" file) + (list "checkout" "--" file))) + (when (setq file (egg-sync-do-file file egg-git-command nil nil args)) + (if (consp file) (setq file (car file))) + (when (stringp file) + (egg-revert-visited-files file))))) + +(defun egg-file-stage-current-file () + (interactive) + (let ((git-dir (egg-git-dir)) + (file (buffer-file-name))) + (when (egg-sync-do-file file egg-git-command nil nil + (list "add" "--" file)) + (message "staged %s modifications" file)))) + +(defun egg-stage-all-files () + (interactive) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir))) + (when (egg-sync-0 "add" "-u") + (message "staged all tracked files's modifications")))) + +(defun egg-stage-untracked-files () + (interactive) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir))) + (when (egg-sync-0 "add" ".") + (message "staged all untracked files")))) + +(defun egg-do-stash-wip (msg) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir))) + (if (egg-repo-clean) + (error "No WIP to stash") + (when (egg-show-git-output + (if (and msg (stringp msg)) + (egg-sync-0 "stash" "save" msg) + (egg-sync-0 "stash" "save")) + 1 "GIT-STASH") + (egg-revert-all-visited-files))))) + +(defun egg-do-checkout (rev) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir))) + (if (egg-sync-0 "checkout" rev) + (egg-revert-all-visited-files)))) + +(defun egg-do-tag (&optional rev prompt force) + (let ((all-refs (egg-all-refs)) + (name (read-string (or prompt "new tag name: "))) + (rev (or rev "HEAD"))) + (when (and (not force) (member name all-refs)) + (error "referene %s already existed!" name)) + (if force + (egg-git-ok nil "tag" "-f" name rev) + (egg-git-ok nil "tag" name rev)))) + +(defun egg-do-create-branch (&optional rev checkout prompt force) + (let ((all-refs (egg-all-refs)) + (name (read-string (or prompt "create new branch: "))) + (rev (or rev "HEAD"))) + (when (and (not force) (member name all-refs)) + (error "referene %s already existed!" name)) + (if (null checkout) + (if force + (egg-git-ok nil "branch" "-f" name rev) + (egg-git-ok nil "branch" name rev)) + (if force + (egg-sync-0 "checkout" "-b" "-f" name rev) + (egg-sync-0 "checkout" "-b" name rev))))) + +(defun egg-do-apply-stash (stash) + (let ((state (egg-repo-state)) + output) + + (setq output (egg-sync-0 "stash" "apply" stash)) + (if output + (egg-revert-all-visited-files) + (message "GIT-STASH> failed to apply %s" stash) + (egg-status nil :sentinel)) + output)) + +(defun egg-do-pop-stash () + (let ((state (egg-repo-state)) + output) + (setq output (egg-sync-0 "stash" "pop")) + (if output + (egg-revert-all-visited-files) + (message "GIT-STASH> failed to pop WIP") + (egg-status nil :sentinel)) + output)) + +(defun egg-do-move-head (rev &optional update-wdir update-index) + (when (egg-show-git-output + (cond (update-wdir (egg-sync-0 "reset" "--hard" rev)) + (update-index (egg-sync-0 "reset" rev)) + (t (egg-sync-0 "reset" "--soft" rev))) + -1 "GIT-RESET") + (if update-wdir (egg-revert-all-visited-files)))) + +(defun egg-do-merge-to-head (rev &optional no-commit) + (let ((msg (concat "merging in " rev)) + (commit-flag (if no-commit "--no-commit" "--commit")) + (pre-merge (egg-get-current-sha1)) + merge-cmd-res modified-files res feed-back) + (with-temp-buffer + (setq merge-cmd-res (egg-git-ok (current-buffer) + "merge" "--log" commit-flag "-m" msg rev)) + (goto-char (point-min)) + (setq modified-files + (egg-git-to-lines "diff" "--name-only" pre-merge)) + (setq feed-back + (save-match-data + (car (nreverse (split-string (buffer-string) + "[\n]+" t))))) + (egg-run-buffers-update-hook) + (list :success merge-cmd-res + :files modified-files + :message feed-back)))) + +(defun egg-do-rebase-head (upstream-or-action + &optional old-base prompt) + (let ((pre-merge (egg-get-current-sha1)) + cmd-res modified-files feed-back old-choices) +;;; (with-temp-buffer + (with-current-buffer (get-buffer-create "*egg-debug*") + (erase-buffer) + (when (and (stringp upstream-or-action) ;; start a rebase + (eq old-base t)) ;; ask for old-base + (unless (egg-git-ok (current-buffer) "rev-list" + "--topo-order" "--reverse" + (concat upstream-or-action "..HEAD^")) + (error "Failed to find rev between %s and HEAD^: %s" + upstream-or-action (buffer-string))) + (unless (egg-git-region-ok (point-min) (point-max) + "name-rev" "--stdin") + (error "Failed to translate revisions: %s" (buffer-string))) + (save-match-data + (goto-char (point-min)) + (while (re-search-forward "^.+(\\(.+\\))$" nil t) + (setq old-choices (cons (match-string-no-properties 1) + old-choices)))) + (setq old-base + (completing-read (or prompt "old base: ") old-choices)) + (erase-buffer)) + + (setq cmd-res + (cond ((and (stringp old-base) (stringp upstream-or-action)) + (egg-git-ok (current-buffer) "rebase" "-m" "--onto" + upstream-or-action old-base)) + ((eq upstream-or-action :abort) + (egg-git-ok (current-buffer) "rebase" "--abort")) + ((eq upstream-or-action :skip) + (egg-git-ok (current-buffer) "rebase" "--skip")) + ((eq upstream-or-action :continue) + (egg-git-ok (current-buffer) "rebase" "--continue")) + ((stringp upstream-or-action) + (egg-git-ok (current-buffer) "rebase" "-m" + upstream-or-action)))) + (goto-char (point-min)) + (setq feed-back + (egg-safe-search-pickup + "^\\(?:CONFLICT\\|All done\\|HEAD is now at\\|Fast-forwarded\\|You must edit all merge conflicts\\).+$")) + (setq modified-files + (egg-git-to-lines "diff" "--name-only" pre-merge)) + (egg-run-buffers-update-hook) + (list :success cmd-res + :message feed-back + :files modified-files)))) + +(defun egg-rm-ref (&optional force name prompt default) + (let* ((refs-alist (egg-ref-type-alist)) + (name (or name (completing-read (or prompt "remove ref: ") + refs-alist nil t + default))) + (type (cdr (assoc name refs-alist)))) + (unless (and name type) + (error "Cannot find reference %s!" name)) + (egg-show-git-output + (cond ((eq :tag type) + (egg-sync-0 "tag" "-d" name)) + ((eq :head type) + (egg-sync-0 "branch" (if force "-vD" "-vd") name)) + ((eq :remote type) + (egg-sync-0 "branch" (if force "-vrD" "-vrd") name))) + -1))) + +;;;======================================================== +;;; log message +;;;======================================================== + +(require 'derived) +(require 'ring) + +(defvar egg-log-msg-ring (make-ring 32)) +(defvar egg-log-msg-ring-idx nil) +(defvar egg-log-msg-action nil) +(defvar egg-log-msg-text-beg nil) +(defvar egg-log-msg-text-end nil) +(defvar egg-log-msg-diff-beg nil) +(define-derived-mode egg-log-msg-mode text-mode "Egg-LogMsg" + "Major mode for editing Git log message.\n\n +\{egg-log-msg-mode-map}." + (setq default-directory (file-name-directory (egg-git-dir))) + (make-local-variable 'egg-log-msg-action) + (set (make-local-variable 'egg-log-msg-ring-idx) nil) + (set (make-local-variable 'egg-log-msg-text-beg) nil) + (set (make-local-variable 'egg-log-msg-text-end) nil) + (set (make-local-variable 'egg-log-msg-diff-beg) nil)) + +(define-key egg-log-msg-mode-map (kbd "C-c C-c") 'egg-log-msg-done) +(define-key egg-log-msg-mode-map (kbd "C-c C-k") 'egg-log-msg-cancel) +(define-key egg-log-msg-mode-map (kbd "M-p") 'egg-log-msg-older-text) +(define-key egg-log-msg-mode-map (kbd "M-n") 'egg-log-msg-newer-text) +(define-key egg-log-msg-mode-map (kbd "C-l") 'egg-buffer-cmd-refresh) + +(defun egg-log-msg-commit () + (let (output) + (setq output + (egg-sync-git-region egg-log-msg-text-beg egg-log-msg-text-end + "commit" "-F" "-")) + (when output + (egg-show-git-output output -1 "GIT-COMMIT") + (egg-run-buffers-update-hook)))) + +(defun egg-log-msg-amend-commit () + (let (output) + (setq output + (egg-sync-git-region egg-log-msg-text-beg egg-log-msg-text-end + "commit" "--amend" "-F" "-")) + (when output + (egg-show-git-output output -1 "GIT-COMMIT-AMEND") + (egg-run-buffers-update-hook)))) + +(defun egg-log-msg-done () + (interactive) + (widen) + (goto-char egg-log-msg-text-beg) + (if (save-excursion (re-search-forward "\\sw\\|\\-" + egg-log-msg-text-end t)) + (when (functionp egg-log-msg-action) + (ring-insert egg-log-msg-ring + (buffer-substring-no-properties egg-log-msg-text-beg + egg-log-msg-text-end)) + (funcall egg-log-msg-action) + (let ((inhibit-read-only t) + (win (get-buffer-window (current-buffer)))) + (erase-buffer) + (if (windowp win) (egg-quit-buffer win)))) + (message "Please enter a log message!") + (ding))) + +(defun egg-log-msg-cancel () + (interactive) + (if (> (length (window-list)) 1) + (delete-window) + (kill-buffer))) + +(defun egg-log-msg-hist-cycle (&optional forward) + "Cycle through message log history." + (let ((len (ring-length egg-log-msg-ring))) + (cond ((<= len 0) + ;; no history + (message "No previous log message.") + (ding)) + ;; don't accidentally throw away unsaved text + ((and (null egg-log-msg-ring-idx) + (> egg-log-msg-text-end egg-log-msg-text-beg) + (not (y-or-n-p "throw away current text? ")))) + ;; do it + (t (delete-region egg-log-msg-text-beg egg-log-msg-text-end) + (setq egg-log-msg-ring-idx + (if (null egg-log-msg-ring-idx) + (if forward + ;; 1st-time + fwd = oldest + (ring-minus1 0 len) + ;; 1st-time + bwd = newest + 0) + (if forward + ;; newer + (ring-minus1 egg-log-msg-ring-idx len) + ;; older + (ring-plus1 egg-log-msg-ring-idx len)))) + (goto-char egg-log-msg-text-beg) + (insert (ring-ref egg-log-msg-ring egg-log-msg-ring-idx)))))) + +(defun egg-log-msg-older-text () + "Cycle backward through comment history." + (interactive) + (egg-log-msg-hist-cycle)) + +(defun egg-log-msg-newer-text () + "Cycle forward through comment history." + (interactive) + (egg-log-msg-hist-cycle t)) + +(defun egg-commit-log-buffer-show-diffs (buf &optional init) + (with-current-buffer buf + (let ((inhibit-read-only t) beg) + (goto-char egg-log-msg-diff-beg) + (delete-region (point) (point-max)) + (setq beg (point)) + + (dolist (sect egg-commit-buffer-sections) + (cond ((eq sect 'staged) + (egg-sb-insert-staged-section "Changes to Commit:" "--stat")) + ((eq sect 'unstaged) + (egg-sb-insert-unstaged-section "Deferred Changes:")) + ((eq sect 'untracked) + (egg-sb-insert-untracked-section)))) + + (put-text-property beg (point) 'read-only t) + (put-text-property beg (point) 'front-sticky nil) + (if init (egg-buffer-maybe-hide-all)) + (force-window-update buf)))) + +(define-egg-buffer commit "*%s-commit@%s*" + (egg-log-msg-mode) + (setq major-mode 'egg-commit-buffer-mode + mode-name "Egg-Commit" + mode-line-process "") + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-commit-log-buffer-show-diffs) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-commit-buffer-mode-hook)) + +(defun egg-commit-log-edit (title-function + action-function + insert-init-text-function) + (interactive (if current-prefix-arg + (list (concat + (egg-text "Amending " 'egg-text-3) + (egg-text (egg-pretty-head-name) 'egg-branch)) + #'egg-log-msg-amend-commit + (egg-commit-message "HEAD")) + (list (concat + (egg-text "Committing into " 'egg-text-3) + (egg-text (egg-pretty-head-name) 'egg-branch)) + #'egg-log-msg-commit + nil))) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir)) + (buf (egg-get-commit-buffer 'create)) + (state (egg-repo-state)) + (head-info (egg-head)) + (head (or (cdr head-info) + (format "Detached HEAD! (%s)" (car head-info)))) + (inhibit-read-only inhibit-read-only)) + (with-current-buffer buf + (setq inhibit-read-only t) + (erase-buffer) + (set (make-local-variable 'egg-log-msg-action) + action-function) + (insert (cond ((functionp title-function) + (funcall title-function state)) + ((stringp title-function) title-function) + (t "Shit happens!")) + "\n" + "Repository: " (egg-text git-dir 'font-lock-constant-face) "\n" + (egg-text "-- Commit Message (type `C-c C-c` when done or `C-c C-k` when cancel) -" + 'font-lock-comment-face)) + (put-text-property (point-min) (point) 'read-only t) + (put-text-property (point-min) (point) 'rear-sticky nil) + (insert "\n") + (set (make-local-variable 'egg-log-msg-text-beg) (point-marker)) + (set-marker-insertion-type egg-log-msg-text-beg nil) + (put-text-property (1- egg-log-msg-text-beg) egg-log-msg-text-beg + :navigation 'commit-log-text) + (insert (egg-prop "\n------------------------ End of Commit Message ------------------------" + 'read-only t 'front-sticky nil + 'face 'font-lock-comment-face)) + (set (make-local-variable 'egg-log-msg-diff-beg) (point-marker)) + (set-marker-insertion-type egg-log-msg-diff-beg nil) + (egg-commit-log-buffer-show-diffs buf 'init) + (goto-char egg-log-msg-text-beg) + (cond ((functionp insert-init-text-function) + (funcall insert-init-text-function)) + ((stringp insert-init-text-function) + (insert insert-init-text-function))) + (set (make-local-variable 'egg-log-msg-text-end) (point-marker)) + (set-marker-insertion-type egg-log-msg-text-end t)) + (pop-to-buffer buf t))) + +;;;======================================================== +;;; diff-mode +;;;======================================================== +(defconst egg-diff-buffer-mode-map + (let ((map (make-sparse-keymap "Egg:DiffBuffer"))) + (set-keymap-parent map egg-buffer-mode-map) + map)) + +(defun egg-diff-buffer-insert-diffs (buffer) + (with-current-buffer buffer + (let ((args (plist-get egg-diff-buffer-info :args)) + (title (plist-get egg-diff-buffer-info :title)) + (prologue (plist-get egg-diff-buffer-info :prologue)) + (src-prefix (plist-get egg-diff-buffer-info :src)) + (dst-prefix (plist-get egg-diff-buffer-info :dst)) + (help (plist-get egg-diff-buffer-info :help)) + (inhibit-read-only t) + pos beg inv-beg help-beg help-end help-inv-beg) + (erase-buffer) + (insert (egg-text title 'egg-section-title) "\n") + (insert prologue "\n") + (setq inv-beg (1- (point))) + (when help + (insert "\n") + (setq help-beg (point)) + (insert (egg-text "Help" 'egg-help-header-1) "\n") + (setq help-inv-beg (1- (point))) + (insert help) + (setq help-end (point))) + (setq pos (point)) + (setq beg (point)) + (apply 'call-process egg-git-command nil t nil "diff" args) + (unless (> (point) beg) + (insert (egg-text "No difference!\n" 'egg-text-4))) + (egg-delimit-section :section 'file (point-min) (point) inv-beg + egg-section-map 'file) + (egg-delimit-section :help 'help help-beg help-end help-inv-beg + egg-section-map 'egg-compute-navigation) + (apply 'egg-decorate-diff-section + :begin (point-min) + :end (point) + :src-prefix src-prefix + :dst-prefix dst-prefix + egg-diff-buffer-info) + (goto-char pos)))) + +(define-egg-buffer diff "*%s-diff@%s*" + "Major mode to display the git diff output." + (kill-all-local-variables) + (setq buffer-read-only t) + (setq major-mode 'egg-diff-buffer-mode + mode-name "Egg-Diff" + mode-line-process "" + truncate-lines t) + (use-local-map egg-diff-buffer-mode-map) + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-diff-buffer-insert-diffs) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-diff-buffer-mode-hook)) + +(defconst egg-diff-buffer-common-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) + (egg-pretty-help-text + "\\\n" + "\\[egg-buffer-cmd-navigate-prev]:previous block " + "\\[egg-buffer-cmd-navigate-next]:next block " + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n"))) + +(defconst egg-diff-buffer-diff-help-heading + (egg-text "Extra Bindings for Diff blocks:" 'egg-help-header-2)) + +(defconst egg-unstaged-diff-help-text + (egg-pretty-help-text + "\\\n" + "\\[egg-diff-section-cmd-stage]:stage file/hunk " + "\\[egg-diff-section-cmd-undo]:undo file/hunk " + "\\[egg-diff-section-cmd-visit-file-other-window]:visit file/line\n")) + +(defconst egg-staged-diff-help-text + (egg-pretty-help-text + "\\\n" + "\\[egg-diff-section-cmd-stage]:unstage file/hunk " + "\\[egg-diff-section-cmd-visit-file-other-window]:visit file/line\n")) + +(defconst egg-plain-diff-help-text + (egg-pretty-help-text + "\\\n" + "\\[egg-diff-section-cmd-visit-file-other-window]:visit file/line\n")) + +(defconst egg-wdir-diff-help-text + (egg-pretty-help-text + "\\\n" + "\\[egg-diff-section-cmd-undo]:undo file/hunk " + "\\[egg-diff-section-cmd-visit-file-other-window]:visit file/line\n")) + +(defun egg-diff-info-add-help (info) + (let ((map (plist-get info :diff-map)) help) + (setq help + (concat egg-diff-buffer-common-help-text + egg-diff-buffer-diff-help-heading + (cond ((eq map egg-unstaged-diff-section-map) + egg-unstaged-diff-help-text) + ((eq map egg-staged-diff-section-map) + egg-staged-diff-help-text) + ((eq map egg-diff-section-map) + egg-plain-diff-help-text) + ((eq map egg-wdir-diff-section-map) + egg-wdir-diff-help-text)))) + (plist-put info :help help))) + +(defun egg-do-diff (diff-info) + (let* ((git-dir (egg-git-dir)) + (dir (file-name-directory git-dir)) + (buf (egg-get-diff-buffer 'create))) + (with-current-buffer buf + (set (make-local-variable 'egg-diff-buffer-info) diff-info) + (egg-diff-buffer-insert-diffs buf)) + buf)) + +(defun egg-build-diff-info (src dst &optional file) + (let* ((git-dir (egg-git-dir)) + (dir (file-name-directory git-dir)) + info tmp) + (setq info + (cond ((and (null src) (null dst)) + (list :args (list "--no-color" "-p" + "--src-prefix=INDEX/" + "--dst-prefix=WORKDIR/") + :title (format "from INDEX to %s" dir) + :prologue "hunks can be removed or added into INDEX." + :src "INDEX/" :dst "WORKDIR/" + :diff-map egg-unstaged-diff-section-map + :hunk-map egg-unstaged-hunk-section-map)) + ((and (equal src "HEAD") (equal dst "INDEX")) + (list :args (list "--no-color" "--cached" "-p" + "--src-prefix=INDEX/" + "--dst-prefix=WORKDIR/") + :title "from HEAD to INDEX" + :prologue "hunks can be removed from INDEX." + :src "HEAD/" :dst "INDEX/" + :diff-map egg-staged-diff-section-map + :hunk-map egg-staged-hunk-section-map)) + ((and (stringp src) (stringp dst)) + (list :args (list "--no-color" "-p" + (concat src ".." dst)) + :title (format "from %s to %s" src dst) + :prologue (format "a: %s\nb: %s" src dst) + :src-revision src + :dst-revision dst + :diff-map egg-diff-section-map + :hunk-map egg-hunk-section-map)) + ((and (stringp src) (null dst)) + (list :args (list "--no-color" "-p" src) + :title (format "from %s to %s" src dir) + :prologue (concat (format "a: %s\nb: %s\n" src dir) + "hunks can be removed???") + :src-revision src + :diff-map egg-wdir-diff-section-map + :hunk-map egg-wdir-hunk-section-map)))) + (if (memq :diff egg-show-key-help-in-buffers) + (egg-diff-info-add-help info)) + (if (stringp file) + (setq file (list file)) + (setq tmp (plist-get info :args)) + (setq tmp (cons "-M" tmp)) + (plist-put info :args tmp)) + (when (consp file) + (setq tmp (plist-get info :prologue)) + (setq tmp (concat (egg-text (mapconcat 'identity file "\n") + 'egg-text-3) + "\n" + (egg-text tmp 'egg-text-1))) + (plist-put info :prologue tmp) + (setq tmp (plist-get info :args)) + (setq tmp (append tmp (cons "--" file))) + (plist-put info :args tmp)) + info)) + +(defun egg-diff-ref (&optional default) + "Prompt a revision to diff other ref." + (interactive (list (car (get-text-property (point) :ref)))) + (let* ((src (completing-read "diff: " (egg-all-refs) + nil nil (or default ""))) + (buf (egg-do-diff (egg-build-diff-info src nil)))) + (pop-to-buffer buf t))) + + +;;;======================================================== +;;; log browsing +;;;======================================================== +(defvar egg-log-buffer-comment-column nil) +(defvar egg-internal-log-buffer-closure nil) + +(defun egg-run-git-log-HEAD (&optional refs-only) + (if refs-only + (egg-git-ok t "log" (format "--max-count=%d" egg-log-HEAD-max-len) + "--graph" "--topo-order" "--simplify-by-decoration" + "--pretty=oneline" "--decorate" "--no-color") + (egg-git-ok t "log" (format "--max-count=%d" egg-log-HEAD-max-len) + "--graph" "--topo-order" + "--pretty=oneline" "--decorate" "--no-color"))) + +(defun egg-run-git-log-all (&optional refs-only) + (if refs-only + (egg-git-ok t "log" (format "--max-count=%d" egg-log-all-max-len) + "--graph" "--topo-order" "--simplify-by-decoration" + "--pretty=oneline" "--decorate" "--all" "--no-color") + (egg-git-ok t "log" (format "--max-count=%d" egg-log-all-max-len) + "--graph" "--topo-order" + "--pretty=oneline" "--decorate" "--all" "--no-color"))) + +(defun egg-run-git-log-pickaxe (string) + (egg-git-ok t "log" "--pretty=oneline" "--decorate" "--no-color" + (concat "-S" string))) + +(defconst egg-log-commit-base-map + (let ((map (make-sparse-keymap "Egg:LogCommitBase"))) + (set-keymap-parent map egg-hide-show-map) + (define-key map (kbd "SPC") 'egg-log-buffer-insert-commit) + (define-key map (kbd "B") 'egg-log-buffer-create-new-branch) + (define-key map (kbd "b") 'egg-log-buffer-start-new-branch) + (define-key map (kbd "o") 'egg-log-buffer-checkout-commit) + (define-key map (kbd "t") 'egg-log-buffer-tag-commit) + (define-key map (kbd "T") 'egg-log-buffer-atag-commit) + (define-key map (kbd "a") 'egg-log-buffer-attach-head) + (define-key map (kbd "m") 'egg-log-buffer-merge) + (define-key map (kbd "r") 'egg-log-buffer-rebase) + (define-key map (kbd "R") 'egg-log-buffer-rebase-interactive) + map)) + +(defconst egg-log-commit-map + (let ((map (make-sparse-keymap "Egg:LogCommit"))) + (set-keymap-parent map egg-log-commit-base-map) + (define-key map (kbd "+") 'egg-log-buffer-mark-pick) + (define-key map (kbd ".") 'egg-log-buffer-mark-squash) + (define-key map (kbd "~") 'egg-log-buffer-mark-edit) + (define-key map (kbd "-") 'egg-log-buffer-unmark) + + (define-key map (kbd "*") 'egg-log-buffer-mark) + (define-key map (kbd "=") 'egg-log-buffer-diff-revs) + + (define-key map [C-down-mouse-2] 'egg-log-popup-commit-line-menu) + (define-key map [C-mouse-2] 'egg-log-popup-commit-line-menu) + + map)) + +(defconst egg-log-ref-map + (let ((map (make-sparse-keymap "Egg:LogRef"))) + (set-keymap-parent map egg-log-commit-map) + (define-key map (kbd "L") 'egg-log-buffer-reflog-ref) + (define-key map (kbd "x") 'egg-log-buffer-rm-ref) + (define-key map (kbd "u") 'egg-log-buffer-push-to-local) + map)) + +(defconst egg-log-local-ref-map + (let ((map (make-sparse-keymap "Egg:LogLocalRef"))) + (set-keymap-parent map egg-log-ref-map) + (define-key map (kbd "U") 'egg-log-buffer-push-to-remote) + (define-key map (kbd "d") 'egg-log-buffer-push-head-to-local) + + (define-key map [C-down-mouse-2] 'egg-log-popup-local-ref-menu) + (define-key map [C-mouse-2] 'egg-log-popup-local-ref-menu) + + map)) + +(defconst egg-log-remote-ref-map + (let ((map (make-sparse-keymap "Egg:LogRemoteRef"))) + (set-keymap-parent map egg-log-ref-map) + (define-key map (kbd "d") 'egg-log-buffer-fetch-remote-ref) + + (define-key map [C-down-mouse-2] 'egg-log-popup-remote-ref-menu) + (define-key map [C-mouse-2] 'egg-log-popup-remote-ref-menu) + + map)) + +(defconst egg-log-remote-site-map + (let ((map (make-sparse-keymap "Egg:LogRef"))) + (set-keymap-parent map egg-log-commit-map) + (define-key map (kbd "d") 'egg-log-buffer-fetch) + (define-key map (kbd "U") 'egg-log-buffer-push) + + (define-key map [C-down-mouse-2] 'egg-log-popup-remote-site-menu) + (define-key map [C-mouse-2] 'egg-log-popup-remote-site-menu) + + map)) + +(defconst egg-log-diff-map + (let ((map (make-sparse-keymap "Egg:LogDiff"))) + (set-keymap-parent map egg-section-map) + (define-key map (kbd "RET") 'egg-log-diff-cmd-visit-file-other-window) + (define-key map (kbd "f") 'egg-log-diff-cmd-visit-file) + (define-key map (kbd "=") 'egg-diff-section-cmd-ediff) + map)) + +(defconst egg-log-hunk-map + (let ((map (make-sparse-keymap "Egg:LogHunk"))) + (set-keymap-parent map egg-section-map) + (define-key map (kbd "RET") 'egg-log-hunk-cmd-visit-file-other-window) + (define-key map (kbd "f") 'egg-log-hunk-cmd-visit-file) + (define-key map (kbd "=") 'egg-diff-section-cmd-ediff) + map)) + +(defconst egg-log-buffer-mode-map + (let ((map (make-sparse-keymap "Egg:LogBuffer"))) + (set-keymap-parent map egg-buffer-mode-map) + (define-key map "n" 'egg-log-buffer-next-ref) + (define-key map "s" 'egg-status) + (define-key map "p" 'egg-log-buffer-prev-ref) + (define-key map "L" 'egg-reflog) + (define-key map "/" 'egg-search-changes) + map)) + + + +(defun egg-decorate-log (&optional line-map head-map tag-map remote-map remote-site-map) + (let ((start (point)) + (head-sha1 (egg-get-current-sha1)) + (ov (make-overlay (point-min) (point-min) nil t)) + (dec-ref-alist + (egg-full-ref-decorated-alist + (list 'face 'egg-branch-mono 'keymap head-map 'help-echo (egg-tooltip-func)) + (list 'face 'egg-tag-mono 'keymap tag-map 'help-echo (egg-tooltip-func)) + (list 'face 'egg-an-tag-mono 'keymap tag-map 'help-echo (egg-tooltip-func)) + (list 'face 'egg-branch-mono 'keymap remote-map 'help-echo (egg-tooltip-func)) + (list 'face 'egg-remote-mono 'keymap remote-site-map 'help-echo (egg-tooltip-func)))) + (ref-string-len 0) + (dashes-len 0) + (min-dashes-len 300) + separator ref-string refs full-refs sha1 + line-props graph-len beg end sha-beg sha-end subject-beg + refs-start refs-end ref-alist + head-line) + (setq ref-alist (mapcar (lambda (pair) + (cons + (substring-no-properties (cdr pair)) + (car pair))) + dec-ref-alist)) + (save-excursion + (while (re-search-forward "\\([0-9a-f]\\{40\\}\\) .+$" nil t) + (setq sha-beg (match-beginning 1) + sha-end (match-end 1) + subject-beg (1+ sha-end) + beg (line-beginning-position) + end (match-end 0) + refs-start nil) + (setq graph-len (if (= beg sha-beg) 0 (- sha-beg beg 1)) + sha1 (buffer-substring-no-properties sha-beg sha-end) + subject-beg (if (/= (char-after subject-beg) ?\() + subject-beg + (setq refs-start (1+ subject-beg)) + (goto-char subject-beg) + (skip-chars-forward "^)") + (setq refs-end (point)) + (+ (point) 2))) + (setq refs (when refs-start + (save-match-data + (mapcar (lambda (lref) + (if (and (>= (length lref) 5) (string-equal (substring lref 0 5) "tag: ")) + (substring lref 5) + (if (and (>= (length lref) 6) (string-equal (substring lref -5) "/HEAD")) + nil + lref))) + (split-string + (buffer-substring-no-properties (+ sha-end 2) + refs-end) + ", +" t))))) + + (setq full-refs (mapcar (lambda (full-ref-name) + (cdr (assoc full-ref-name ref-alist))) + refs)) + + ;; common line decorations + (setq line-props (list :navigation sha1 :commit sha1)) + + (if line-map + (setq line-props (nconc (list 'keymap line-map) + line-props))) + (when refs + (setq line-props (nconc (list :references refs) + line-props))) + + + (setq separator (apply 'propertize " " line-props)) + (setq ref-string + (if full-refs + (propertize + (mapconcat (lambda (full-ref-name) + (cdr (assoc full-ref-name + dec-ref-alist))) + full-refs separator) + :navigation sha1 :commit sha1 + :references refs))) + (setq ref-string-len (if ref-string (length ref-string))) + + ;; entire line + (add-text-properties beg (1+ end) line-props) + + ;; comment + (put-text-property subject-beg end 'face 'egg-text-2) + ;; delete refs list (they're already parsed) + (if refs-start + (delete-region (1- refs-start) (+ refs-end 2))) + + ;; shorten sha + (delete-region (+ sha-beg 8) sha-end) + (put-text-property sha-beg (+ sha-beg 8) + 'face 'font-lock-constant-face) + (put-text-property sha-beg (+ sha-beg 8) + 'help-echo (egg-tooltip-func)) + + (setq dashes-len (- 300 graph-len 1 + (if refs (1+ ref-string-len) 0))) + (setq min-dashes-len (min min-dashes-len dashes-len)) + + (put-text-property sha-beg (1+ sha-beg) + :dash-refs + (apply 'concat + (apply 'propertize + (make-string dashes-len ?-) + (nconc (list 'face 'egg-graph) + line-props)) + separator + (if refs + (list ref-string separator)))) +;;; (when (string= sha1 head-sha1) +;;; (overlay-put ov 'face 'egg-log-HEAD) +;;; (overlay-put ov 'evaporate t) +;;; (move-overlay ov beg (1+ (line-end-position)))) + (when (string= sha1 head-sha1) + (setq head-line (point-marker))) + + (goto-char (line-end-position))) + + (if (= min-dashes-len 300) + (insert (egg-text "nothing found!" 'egg-warning)) + + + ;; compute how many dashes can be deleted while + ;; leaving at least 1 dash + (setq min-dashes-len (1- min-dashes-len)) + + ;; before cut + ;; type a: 300 = graph spc dashes + ;; type b: 300 = graph spc dashes spc ref-string + ;; + ;; after cut + ;; type a: 300 - min-dashes-len = graph spc dashes + ;; type b: 300 - min-dashes-len = graph spc dashes spc ref-string + ;; + ;; a: comment-column = graph spc dashes spc sha1-8 spc + ;; b: comment-column = graph spc dashes spc ref-string spc sha1-8 spc + ;; need to remove the 1st spc if graph-len = 0 + (set (make-local-variable 'egg-log-buffer-comment-column) + (+ (- 300 min-dashes-len (if (> graph-len 0) 0 1)) 1 8 1)) + + (when (and (> min-dashes-len 0)) + (goto-char (1- start)) + (while (setq start (next-single-property-change (point) + :dash-refs)) + (goto-char start) + (insert (substring (get-text-property start :dash-refs) + min-dashes-len)) + (forward-char 2))) + + (when head-line + (goto-char head-line) + (overlay-put ov 'face 'egg-log-HEAD) + (overlay-put ov 'evaporate t) + (move-overlay ov (line-beginning-position) + (1+ (line-end-position)))) + head-line)))) + +(defsubst egg-log-buffer-insert-n-decorate-logs (log-insert-func) + (let ((beg (point))) + (funcall log-insert-func) + (goto-char beg) + (egg-decorate-log egg-log-commit-map + egg-log-local-ref-map + egg-log-local-ref-map + egg-log-remote-ref-map + egg-log-remote-site-map))) + + +(defun egg-log-diff-cmd-visit-file (file sha1) + (interactive (list (car (get-text-property (point) :diff)) + (get-text-property (point) :commit))) + (pop-to-buffer (egg-file-get-other-version file sha1 nil t))) + +(defun egg-log-diff-cmd-visit-file-other-window (file sha1) + (interactive (list (car (get-text-property (point) :diff)) + (get-text-property (point) :commit))) + (pop-to-buffer (egg-file-get-other-version file sha1 nil t) t)) + +(defun egg-log-hunk-cmd-visit-file (sha1 file hunk-header hunk-beg &rest ignored) + (interactive (cons (get-text-property (point) :commit) + (egg-hunk-info-at (point)))) + (let ((line (egg-hunk-compute-line-no hunk-header hunk-beg))) + (pop-to-buffer (egg-file-get-other-version file sha1 nil t)) + (goto-line line))) + +(defun egg-log-hunk-cmd-visit-file-other-window (sha1 file hunk-header hunk-beg &rest ignored) + (interactive (cons (get-text-property (point) :commit) + (egg-hunk-info-at (point)))) + (let ((line (egg-hunk-compute-line-no hunk-header hunk-beg))) + (pop-to-buffer (egg-file-get-other-version file sha1 nil t) t) + (goto-line line))) + +(defun egg-log-buffer-get-rev-at (pos &rest options) + (let* ((commit (get-text-property pos :commit)) + (refs (get-text-property pos :references)) + (first-head (if (stringp refs) refs (car (last refs)))) + (ref-at-point (car (get-text-property pos :ref))) + (head-sha1 (egg-get-current-sha1))) + (if (and (not (memq :no-HEAD options)) (string= head-sha1 commit)) + "HEAD" + (or ref-at-point first-head + (if (memq :symbolic options) + (egg-describe-rev commit) + commit))))) + +(defun egg-log-buffer-do-remove-mark (mark-char) + (let ((pos (point-min)) + (inhibit-read-only t)) + (while (setq pos (next-single-property-change (1+ pos) :mark)) + (when (= (get-text-property pos :mark) mark-char) + (remove-text-properties pos (1+ pos) + (list :mark nil 'display nil)))))) + +(defun egg-log-buffer-find-first-mark (mark-char) + (let ((pos (point-min))) + (while (and (setq pos (next-single-property-change (1+ pos) :mark)) + (/= (get-text-property pos :mark) mark-char))) + pos)) + +(defun egg-log-buffer-do-mark (pos char &optional unmark remove-first) + (let ((commit (get-text-property pos :commit)) + (inhibit-read-only t) + (col (- egg-log-buffer-comment-column 10)) + (step (if unmark -1 (if remove-first 0 1)))) + (when commit + (when remove-first + (egg-log-buffer-do-remove-mark char)) + (move-to-column col) + (funcall (if unmark + #'remove-text-properties + #'add-text-properties) + (point) (1+ (point)) + (list :mark char + 'display + (and char + (egg-text (char-to-string char) + 'egg-log-buffer-mark)))) + (forward-line step) + (while (not (or (get-text-property pos :commit) + (eobp) (bobp))) + (forward-line step)) + (move-to-column col)))) + +(defun egg-log-buffer-mark (pos) + (interactive "d") + (egg-log-buffer-do-mark pos ?* nil t)) + +(defun egg-log-buffer-mark-pick (pos) + (interactive "d") + (egg-log-buffer-do-mark pos ?+)) + +(defun egg-log-buffer-mark-squash (pos) + (interactive "d") + (egg-log-buffer-do-mark pos ?.)) + +(defun egg-log-buffer-mark-edit (pos) + (interactive "d") + (egg-log-buffer-do-mark pos ?~)) + +(defun egg-log-buffer-do-unmark-all () + (interactive) + (let ((pos (point-min)) + (inhibit-read-only t)) + (while (setq pos (next-single-property-change (1+ pos) :mark)) + (remove-text-properties pos (1+ pos) + (list :mark nil 'display nil))))) + +(defun egg-log-buffer-unmark (pos &optional all) + (interactive "d\nP") + (if all + (egg-log-buffer-do-unmark-all) + (egg-log-buffer-do-mark pos nil t))) + +(defun egg-log-buffer-get-marked-alist () + (let ((pos (point-min)) + marker subject alist) + (save-excursion + (while (setq pos (next-single-property-change (1+ pos) :mark)) + (goto-char pos) + (setq marker (point-marker)) + (move-to-column egg-log-buffer-comment-column) + (setq subject (buffer-substring-no-properties + (point) (line-end-position))) + (setq alist (cons (list (get-text-property pos :commit) + (get-text-property pos :mark) + subject marker) + alist)))) + alist)) + + +(defun egg-setup-rebase-interactive (rebase-dir upstream onto repo-state commit-alist) + (let ((process-environment process-environment) + (repo-state (or repo-state (egg-repo-state :staged :unstaged))) + (orig-buffer (current-buffer)) + orig-head-sha1) + (setq orig-head-sha1 (plist-get repo-state :sha1)) + (unless (egg-repo-clean repo-state) (error "Repo not clean")) + (unless onto (setq onto upstream)) + + (with-temp-buffer + (make-directory rebase-dir t) + + (write-region (point-min) (point-min) + (concat rebase-dir "interactive")) + (insert (plist-get repo-state :head) "\n") + (write-region (point-min) (point-max) + (concat rebase-dir "head-name")) + (erase-buffer) + (insert (plist-get repo-state :sha1) "\n") + (write-region (point-min) (point-max) + (concat rebase-dir "head")) + (erase-buffer) + (insert upstream "\n") + (write-region (point-min) (point-max) + (concat rebase-dir "upstream")) + (erase-buffer) + (insert onto "\n") + (write-region (point-min) (point-max) + (concat rebase-dir "onto")) + (erase-buffer) + (insert "# Rebase " upstream ".." orig-head-sha1 " onto " onto "\n") + (dolist (rev-info commit-alist) + (insert (cond ((eq (nth 1 rev-info) ?+) "pick") + ((eq (nth 1 rev-info) ?.) "squash") + ((eq (nth 1 rev-info) ?~) "edit")) + " " (nth 0 rev-info) " " (nth 2 rev-info) "\n")) + (write-region (point-min) (point-max) + (concat rebase-dir "git-rebase-todo")) + (write-region (point-min) (point-max) + (concat rebase-dir "git-rebase-todo.backup"))) + + (setenv "GIT_REFLOG_ACTION" (format "rebase -i (%s)" onto)) + (with-current-buffer (get-buffer-create "*egg-debug*") + (egg-git-ok nil "update-ref" "ORIG_HEAD" orig-head-sha1) + (egg-git-ok nil "checkout" onto) + (egg-do-async-rebase-continue #'egg-handle-rebase-interactive-exit + orig-head-sha1)))) + +(defun egg-handle-rebase-interactive-exit (&optional orig-sha1) + (let ((exit-msg egg-async-exit-msg) + (proc egg-async-process) + state buffer res msg rebase-dir) + (goto-char (point-min)) + (save-match-data + (re-search-forward + (eval-when-compile + (concat "\\<\\(?:" + "\\(please commit in egg.+$\\)" "\\|" + "\\(Successfully rebased and updated.+$\\)" "\\|" + "\\(You can amend the commit now\\)" "\\|" + "\\(Automatic cherry-pick failed\\)" "\\|" + "\\(nothing added to commit\\)" "\\|" + "\\(\\(?:Cannot\\|Could not\\).+\\)" "\\)")) nil t) + (setq msg (match-string-no-properties 0)) + (setq res (cond ((match-beginning 1) :rebase-commit) + ((match-beginning 2) :rebase-done) + ((match-beginning 3) :rebase-edit) + ((match-beginning 4) :rebase-conflict) + ((match-beginning 5) :rebase-empty) + ((match-beginning 6) :rebase-fail)))) + (setq buffer (process-get proc :orig-buffer)) + (with-current-buffer buffer + (egg-run-buffers-update-hook) + (egg-revert-all-visited-files) ;; too heavy ??? + (setq state (egg-repo-state :force)) + (setq rebase-dir (plist-get state :rebase-dir)) + (cond ((eq res :rebase-done) + (message "GIT-REBASE-INTERACTIVE: %s" msg)) + + ((eq res :rebase-commit) + (egg-commit-log-edit + (let* ((cherry (plist-get state :rebase-cherry)) + (cherry-op (save-match-data + (car (split-string cherry))))) + (concat + (egg-text "Rebasing " 'egg-text-3) + (egg-text (plist-get state :rebase-head) 'egg-branch) + ": " + (egg-text (concat "Commit " cherry-op "ed cherry") + 'egg-text-3))) + `(lambda () + (let ((process-environment process-environment)) + (mapcar (lambda (env-lst) + (setenv (car env-lst) (cadr env-lst))) + (egg-rebase-author-info ,rebase-dir)) + (egg-log-msg-commit)) + (with-current-buffer ,buffer + (egg-do-async-rebase-continue + #'egg-handle-rebase-interactive-exit + ,orig-sha1))) + (egg-file-as-string (concat rebase-dir "message")))) + + + ((eq res :rebase-edit) + (egg-commit-log-edit + (concat (egg-text "Rebasing " 'egg-text-3) + (egg-text (plist-get state :rebase-head) + 'egg-branch) ": " + (egg-text "Re-edit cherry's commit log" + 'egg-text-3)) + `(lambda () + (let ((process-environment process-environment)) + (mapcar (lambda (env-lst) + (setenv (car env-lst) (cadr env-lst))) + (egg-rebase-author-info ,rebase-dir)) + (egg-log-msg-amend-commit)) + (with-current-buffer ,buffer + (egg-do-async-rebase-continue + #'egg-handle-rebase-interactive-exit + ,orig-sha1))) + (egg-commit-message "HEAD"))) + + ((eq res :rebase-conflict) + (egg-status nil :sentinel) + (ding) + (message "automatic rebase stopped! please resolve conflict(s)")) + ((eq res :rebase-empty) + (egg-status nil :sentinel) + (ding) + (message "automatic rebase stopped! this commit should be skipped!")) + ((eq res :rebase-fail) + (egg-status nil :sentinel) + (ding) + (message "Automatic rebase failed!")))))) + +(defun egg-log-buffer-merge (pos &optional no-commit) + (interactive "d\nP") + (let ((rev (egg-log-buffer-get-rev-at pos :symbolic :no-HEAD)) + res modified-files buf) + (unless (egg-repo-clean) + (egg-status) + (error "Repo is not clean!")) + (if (null (y-or-n-p (format "merge %s to HEAD? " rev))) + (message "cancel merge from %s to HEAD!" rev) + (setq res (egg-do-merge-to-head rev no-commit)) + (setq modified-files (plist-get res :files)) + (if modified-files + (egg-revert-visited-files modified-files)) + (message "GIT-MERGE> %s" (plist-get res :message)) + (unless (and (plist-get res :success) (null no-commit)) + (egg-status))))) + +(defun egg-log-buffer-rebase (pos &optional move) + (interactive "d\nP") + (let ((rev (egg-log-buffer-get-rev-at pos :symbolic :no-HEAD)) + res modified-files buf) + (if (null (y-or-n-p (format "rebase HEAD to %s? " rev))) + (message "cancel rebase HEAD to %s!" rev) + (unless (egg-buffer-do-rebase + rev (if move t) + (if move + (format "starting point to rebase HEAD onto %s: " + rev))) + (egg-status))))) + +(defun egg-log-buffer-rebase-interactive (pos &optional move) + (interactive "d\nP") + (let* ((state (egg-repo-state :staged :unstaged)) + (rebase-dir (concat (plist-get state :gitdir) "/" + egg-git-rebase-subdir "/")) + (todo-alist (egg-log-buffer-get-marked-alist)) + (commits (mapcar 'car todo-alist)) + (upstream (egg-commit-at pos)) + (all (egg-git-to-lines "rev-list" "--reverse" "--cherry-pick" + (concat upstream "..HEAD")))) + (unless (egg-repo-clean state) + (error "repo %s is not clean" (plist-get state :gitdir))) + (mapc (lambda (commit) + (unless (member commit all) + (error "commit %s is not between HEAD and upstream %s" + commit upstream))) + commits) + + (egg-setup-rebase-interactive rebase-dir upstream nil + state todo-alist) + (egg-status))) + +(defun egg-log-buffer-checkout-commit (pos) + (interactive "d") + (egg-do-checkout + (completing-read "checkout: " (egg-all-refs) nil nil + (egg-log-buffer-get-rev-at pos :symbolic :no-HEAD)))) + +(defun egg-log-buffer-tag-commit (pos &optional force) + (interactive "d\nP") + (let ((rev (egg-log-buffer-get-rev-at pos))) + (when (egg-do-tag rev (format "tag %s with name: " rev) force) + (funcall egg-buffer-refresh-func (current-buffer))))) + +(defun egg-log-buffer-atag-commit (pos &optional force) + (interactive "d\nP") + (let ((commit (get-text-property pos :commit))) + (egg-create-annotated-tag + (read-string (format "create annotated tag on %s with name: " + (egg-describe-rev commit))) + commit))) + +(defun egg-log-buffer-create-new-branch (pos &optional force) + (interactive "d\nP") + (let ((rev (egg-log-buffer-get-rev-at pos))) + (when (egg-do-create-branch + rev nil + (format "create new branch at %s with name: " rev) + force) + (funcall egg-buffer-refresh-func (current-buffer))))) + +(defun egg-log-buffer-start-new-branch (pos &optional force) + (interactive "d\nP") + (let ((rev (egg-log-buffer-get-rev-at pos :symbolic :no-HEAD))) + (when (egg-do-create-branch + rev 'checkout + (format "start new branch from %s with name: " rev) + force)))) + +(defun egg-log-buffer-attach-head (pos &optional strict-level) + (interactive "d\np") + (let* ((rev (egg-log-buffer-get-rev-at pos :symbolic :no-HEAD)) + (commit (egg-commit-at-point)) + (branch (egg-current-branch)) + (update-index (> strict-level 3)) + (update-wdir (> strict-level 15)) + (prompt (format "%s to %s%s? " + (if branch + (concat "move " branch) + "attach HEAD") + (if branch (substring commit 0 8) rev) + (cond (update-wdir " (and update workdir)") + (update-index " (and update index)") + (t ""))))) + (if (y-or-n-p prompt) + (egg-do-move-head (if branch commit rev) + update-wdir update-index)))) + + +(defun egg-log-buffer-rm-ref (pos &optional force) + (interactive "d\nP") + (let ((refs (get-text-property pos :references)) + (ref-at-point (car (get-text-property pos :ref))) + victim) + (unless ref-at-point + (setq ref-at-point (last refs))) + (setq victim (completing-read "remove reference: " refs + nil nil ref-at-point)) + (when (egg-rm-ref force victim) + (funcall egg-buffer-refresh-func (current-buffer))))) + +(defun egg-log-buffer-fetch-remote-ref (pos) + (interactive "d") + (let* ((ref-at-point (get-text-property pos :ref)) + (ref (car ref-at-point)) + (type (cdr ref-at-point)) + name remote) + (unless (eq type :remote) + (error "Nothing to fetch from here!")) + (setq name (file-name-nondirectory ref) + remote (egg-rbranch-to-remote ref)) + (when (and remote name) + (message "GIT> fetching %s from %s..." ref remote) + (egg-buffer-async-do nil "fetch" remote + (format "refs/heads/%s:refs/remotes/%s" + name ref))))) + +(defun egg-log-buffer-fetch (pos) + (interactive "d") + (let* ((ref-at-point (get-text-property pos :ref)) + (ref (car ref-at-point)) + (type (cdr ref-at-point)) + site name def remote) + (unless (eq type :remote) + (error "No site here to fetch from!")) + (setq remote (egg-rbranch-to-remote ref)) + (when remote + (setq name (read-string (format "fetch from %s (default all): " + remote) nil nil "--all")) + (if (equal name "--all") + (progn + (message "GIT> fetching everything from %s..." remote) + (egg-buffer-async-do nil "fetch" remote)) + (message "GIT> fetching %s from %s..." name remote) + (egg-buffer-async-do nil "fetch" remote + (format "refs/heads/%s:refs/remotes/%s/%s" + name remote name)))))) + +(defun egg-log-buffer-push-to-local (pos &optional non-ff) + (interactive "d\nP") + (let* ((src (car (get-text-property pos :ref))) + dst) + (unless src + (error "Nothing to push here!")) + (setq dst (completing-read (format "use %s to update: " src) + (egg-local-refs) nil t)) + (when (egg-show-git-output + (egg-sync-0 "push" "." (if non-ff "-vf" "-v") + (concat src ":" dst)) + -1 "GIT-PUSH") + (funcall egg-buffer-refresh-func (current-buffer))))) + +(defun egg-log-buffer-push-head-to-local (pos &optional non-ff) + (interactive "d\nP") + (let* ((dst (car (get-text-property pos :ref)))) + (unless dst + (error "Nothing here to push to!")) + (if (y-or-n-p (format "update %s with HEAD? " dst)) + (when (egg-show-git-output + (egg-sync-0 "push" "." (if non-ff "-vf" "-v") + (concat "HEAD:" dst)) + -1 "GIT-PUSH") + (funcall egg-buffer-refresh-func (current-buffer)))))) + +(defun egg-log-buffer-push-to-remote (pos &optional non-ff) + (interactive "d\nP") + (let* ((ref-at-point (get-text-property pos :ref)) + (lref (car ref-at-point)) + (type (cdr ref-at-point)) + rref tracking remote spec) + (unless ref-at-point + (error "Nothing to push here!")) + (cond ((eq type :remote) ;; delete a remote head + (setq rref (file-name-nondirectory lref)) + (setq remote (directory-file-name + (file-name-directory lref))) + (setq lref "")) + ((eq type :head) + (setq tracking (egg-tracking-target lref :remote)) + (if (consp tracking) + (setq rref (car tracking) remote (cdr tracking)) + (setq remote (egg-read-remote + (format "push branch %s to remote: " lref))) + (setq rref (read-string + (format "push branch %s to %s as: " lref remote) + lref)))) + ((eq type :tag) + (setq remote (egg-read-remote "push to remote: ")) + (setq rref (read-string + (format "remote tag to push at (on %s): " remote) + lref)) + (setq lref (read-string + (format "local tag to push at %s/%s (empty mean delete the remote tag) : " + remote rref) + rref)))) + (unless (> (length lref) 0) + (unless (y-or-n-p (format "delete %s/%s? " remote rref)) + (message "cancel removal of %s/%s" remote rref) + (setq remote nil rref nil lref nil))) + (when (and remote rref lref) + (setq spec (concat lref ":" rref)) + (message "GIT> pushing %s to %s on %s..." lref rref remote) + (egg-buffer-async-do nil "push" (if non-ff "-vf" "-v") + remote spec)))) + +(defun egg-log-buffer-push (pos) + (interactive "d") + (let* ((ref-at-point (get-text-property pos :ref)) + (ref (car ref-at-point)) + (type (cdr ref-at-point)) + site name def remote) + (unless (eq type :remote) + (error "No site here to push to!")) + (setq remote (egg-rbranch-to-remote ref)) + (when remote + (setq name + (completing-read (format "push to %s (default all heads): " + remote) + (egg-local-refs) nil nil nil nil "--all")) + (message "GIT> pushing %s to %s..." + (if (equal name "--all") "everything" name) remote) + (egg-buffer-async-do nil "push" remote name)))) + +(defun egg-log-buffer-goto-pos (pos) + (goto-char pos) + (goto-char (line-beginning-position)) + (let ((sha1 (get-text-property (point) :commit))) + (when (stringp sha1) + (setq sha1 (substring sha1 0 6)) + (save-match-data + (if (looking-at (concat "^.* \\(" sha1 "\\)")) + (goto-char (match-beginning 1))))))) + +(defun egg-log-buffer-next-ref (pos) + (interactive "d") + (let ((current-ref (get-text-property pos :references)) + (n-pos (next-single-property-change pos :references)) + n-ref) + (when n-pos + (setq n-ref (get-text-property n-pos :references)) + (if n-ref + (egg-log-buffer-goto-pos n-pos) + (if (setq n-pos (next-single-property-change n-pos :references)) + (egg-log-buffer-goto-pos n-pos)))))) + +(defun egg-log-buffer-prev-ref (pos) + (interactive "d") + (let ((current-ref (get-text-property pos :references)) + (p-pos (previous-single-property-change pos :references)) + p-ref) + (when p-pos + (setq p-pos (1- p-pos)) + (setq p-ref (get-text-property p-pos :references)) + (if (and p-ref (not (equal p-ref current-ref))) + (egg-log-buffer-goto-pos p-pos) + (when (setq p-pos (previous-single-property-change p-pos :references)) + (setq p-pos (1- p-pos)) + (egg-log-buffer-goto-pos p-pos)))))) + +(defun egg-log-buffer-do-insert-commit (pos) + (save-excursion + (let ((sha1 (get-text-property pos :commit)) + (ref (get-text-property pos :references)) + (nav (get-text-property pos :navigation)) + (inhibit-read-only t) + (indent-column egg-log-buffer-comment-column) + (indent-spaces (make-string egg-log-buffer-comment-column ? )) + beg end) + (goto-char pos) + (goto-char (1+ (line-end-position))) + (setq beg (point)) + (unless (egg-git-ok t "log" "--max-count=1" "-p" "-M" "--no-color" + (concat + "--pretty=format:" + indent-spaces "%ai%n" + indent-spaces "%an%n%n" + "%b%n" + ) + sha1) + (error "error calling git log %s!" ref)) + (setq end (point)) + (egg-delimit-section :commit sha1 beg end (1- beg) nil nav) + (put-text-property beg end 'keymap egg-section-map) + (egg-decorate-diff-section :begin beg + :end end + :diff-map egg-log-diff-map + :hunk-map egg-log-hunk-map) + (goto-char beg) + (setq end (next-single-property-change beg :diff)) + (put-text-property beg (+ indent-column beg) 'face 'egg-diff-none) + (put-text-property (+ indent-column beg) (line-end-position) + 'face 'egg-text-2) + (forward-line 1) + (put-text-property (point) (+ indent-column (point)) 'face 'egg-diff-none) + (put-text-property (+ indent-column (point)) end 'face 'egg-text-2) + (set-buffer-modified-p nil)))) + +(defun egg-log-buffer-insert-commit (pos) + (interactive "d") + (let* ((next (next-single-property-change pos :diff)) + (sha1 (and next (get-text-property next :commit)))) + (unless (equal (get-text-property pos :commit) sha1) + (egg-log-buffer-do-insert-commit pos)))) + +(defun egg-generic-display-logs (data &optional init) + (buffer-disable-undo) + (and init (setq buffer-invisibility-spec nil)) + (let ((title (plist-get data :title)) + (subtitle (plist-get data :subtitle)) + (git-dir (egg-git-dir)) + (desc (plist-get egg-internal-log-buffer-closure :description)) + (closure (plist-get egg-internal-log-buffer-closure :closure)) + (help (plist-get egg-internal-log-buffer-closure :help)) + (inhibit-read-only t) + inv-beg beg help-beg) + (erase-buffer) + (insert title + (if subtitle (concat "\n" subtitle "\n") "\n") + (egg-text "repo: " 'egg-text-2) + (egg-text (egg-git-dir) 'font-lock-constant-face) + (if desc (concat "\n" desc "\n") "\n") + "\n") + (setq inv-beg (- (point) 2)) + (when (stringp help) + (setq help-beg (point)) + (insert (egg-text "Help" 'egg-help-header-1) "\n") + (put-text-property help-beg (point) 'help-echo (egg-tooltip-func)) + (setq inv-beg (1- (point))) + (insert help "\n")) + (setq beg (point)) + (when help-beg + (egg-delimit-section :section :help help-beg (point) + inv-beg egg-section-map :help)) + (if init (egg-buffer-maybe-hide-help :help)) + (goto-char (or (funcall closure) beg)))) + +(defun egg-log-buffer-redisplay (buffer &optional init) + (with-current-buffer buffer + (let* ((state (egg-repo-state)) + (sha1 (plist-get state :sha1))) + (plist-put egg-internal-log-buffer-closure :title + (egg-text (egg-pretty-head-string state) 'egg-branch)) + (plist-put egg-internal-log-buffer-closure :subtitle + (egg-text sha1 'font-lock-string-face)) + (egg-generic-display-logs egg-internal-log-buffer-closure init)))) + +(defun egg-log-buffer-redisplay-from-command (buffer) + ;; in process buffer + (when (and (processp egg-async-process) + (equal (current-buffer) (process-buffer egg-async-process))) + (or + (save-excursion + (let ((cmd "GIT>") cmd-sexp cmd-string pos done) + (goto-char (point-min)) + (skip-chars-forward "^(") + (setq cmd-sexp (read (current-buffer))) + (when (consp cmd-sexp) + (setq cmd-string (car cmd-sexp) + cmd (cond ((string-equal "fetch" cmd-string) "GIT-FETCH>") + ((string-equal "push" cmd-string) "GIT-PUSH>")))) + (goto-char (point-min)) + (save-match-data + (cond ((re-search-forward "^\\(?:From\\|To\\) \\(.+\\)\n\\(.+\\)$" nil t) + (message "%s %s: %s" cmd + (match-string-no-properties 1) + (match-string-no-properties 2)) + (setq done t)))) + (unless done + (goto-char (point-min)) + (save-match-data + (cond ((re-search-forward "^fatal: \\(.+\\)$" nil t) + (message "%s fatal: %s" cmd + (match-string-no-properties 1)) + (setq done t))))))))) + ;; update log buffer + (egg-log-buffer-redisplay buffer)) + +(define-egg-buffer log "*%s-log@%s*" + "Major mode to display the output of git log.\\ +Each line with a shorten sha1 representing a commit in the repo's history. +\\[egg-log-buffer-next-ref] move the cursor to the next commit with a ref +\\[egg-log-buffer-prev-ref] move the cursor to the previous commit line with a ref. +\\[egg-buffer-cmd-refresh] refresh the display of the log buffer +\\[egg-status] shows the repo's current status. + +\\{egg-log-buffer-mode-map} + +Each line representing a commit has extra keybindings:\\ +\\[egg-log-buffer-insert-commit] fetch and show the commit's details. +\\[egg-section-cmd-toggle-hide-show] hide/show the current commit's details +\\[egg-section-cmd-toggle-hide-show-children] hide all the sub-blocks of the current commit's details. +\\[egg-log-buffer-create-new-branch] create a new branch starting from the current commit. +\\[egg-log-buffer-start-new-branch] start in a new branch from the current commit. +\\[egg-log-buffer-checkout-commit] checkout the current commit. +\\[egg-log-buffer-tag-commit] create a new lightweight tag pointing at the current commit. +\\[egg-log-buffer-attach-head] move HEAD (and maybe the current branch tip) to the +current commit (the underlying git command is `reset --soft'. +C-u \\[egg-log-buffer-attach-head] move HEAD (and maybe the current branch tip) as well as +the index to the current commit (the underlying git command +is `reset --mixed'.) +C-u C-u \\[egg-log-buffer-attach-head] move HEAD (and maybe the current branch tip) and +the index to the current commit, the work dir will also be +updated (the underlying git command is `reset --hard'). +\\[egg-log-buffer-merge] will merge the current commit into HEAD. +C-u \\[egg-log-buffer-merge] will merge the current commit into HEAD but will not +auto-commit if the merge was successful. + +\\{egg-log-commit-map} + +Each ref on the commit line has extra extra keybindings:\\ +\\[egg-log-buffer-rm-ref] delete the ref under the cursor. +\\[egg-log-buffer-push-to-local] update another local ref using the ref under the cursor. + +Each local ref on the commit line has extra extra extra keybindings:\\ +\\[egg-log-buffer-push-to-remote] upload to a remote the ref under the cursor. + for a remote-tracking local branch this would updating the tracking target. + for other local refs this means uploading (or deleting) the local value + of the ref to the remote repository. +\\[egg-log-buffer-push-head-to-local] update the local ref under the cursor with the current HEAD. + +Each remote ref on the commit line has extra extra extra keybindings:\\ +\\[egg-log-buffer-fetch-remote-ref] download the new value of the ref from the remote repo. +." + (kill-all-local-variables) + (setq buffer-read-only t) + (setq major-mode 'egg-log-buffer-mode + mode-name "Egg-Log" + mode-line-process "" + truncate-lines t) + (use-local-map egg-log-buffer-mode-map) + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-log-buffer-redisplay) + (set (make-local-variable 'egg-buffer-async-cmd-refresh-func) + 'egg-log-buffer-redisplay-from-command) + (set (make-local-variable 'egg-log-buffer-comment-column) 0) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-log-buffer-mode-hook)) + +(defun egg-commit-at-point () + (get-text-property (point) :commit)) + +(defun egg-ref-at-point () + (get-text-property (point) :ref)) + +(defun egg-head-at-point () + (eq (cdr (get-text-property (point) :ref)) :head)) + +(defun egg-tag-at-point () + (eq (cdr (get-text-property (point) :ref)) :tag)) + +(defun egg-remote-at-point () + (eq (cdr (get-text-property (point) :ref)) :remote)) + +(defun egg-references-at-point () + (get-text-property (point) :references)) + +(defun egg-log-commit-line-menu-attach-head-index (pos) + (interactive "d") + (egg-log-buffer-attach-head pos 4)) + +(defun egg-log-commit-line-menu-attach-head-index-wdir (pos) + (interactive "d") + (egg-log-buffer-attach-head pos 16)) + + +(defun egg-log-make-commit-line-menu (&optional heading) + (let ((map (make-sparse-keymap heading))) + (define-key map [load] (list 'menu-item "(Re)Load Commit Details" + 'egg-log-buffer-insert-commit + :visible '(egg-commit-at-point))) + (define-key map [diff] (list 'menu-item "Compare against HEAD (or BASE)" + 'egg-log-buffer-diff-revs + :visible '(egg-commit-at-point))) + (define-key map [prev] (list 'menu-item "Goto Prev Ref" + 'egg-log-buffer-prev-ref + :visible '(egg-navigation-at-point))) + (define-key map [next] (list 'menu-item "Goto Next Ref" + 'egg-log-buffer-next-ref + :visible '(egg-navigation-at-point))) + (define-key map [hs] (list 'menu-item "Hide/Show Details" + 'egg-section-cmd-toggle-hide-show + :visible '(egg-navigation-at-point))) + (define-key map [hs-sub] (list 'menu-item "Hide/Show Details of Subsections" + 'egg-section-cmd-toggle-hide-show-children + :visible '(egg-navigation-at-point))) + (define-key map [sp9] '("--")) + (define-key map [rpush] (list 'menu-item "Fetch Refs from Remote" + 'egg-log-buffer-fetch + :visible '(egg-remote-at-point))) + (define-key map [rfetch] (list 'menu-item "Push Refs to Remote" + 'egg-log-buffer-push + :visible '(egg-remote-at-point))) + (define-key map [rdown] (list 'menu-item "Fetch Remote Ref" + 'egg-log-buffer-fetch-remote-ref + :visible '(egg-ref-at-point) + :enable '(egg-remote-at-point))) + (define-key map [ldown] (list 'menu-item "Push HEAD To Ref" + 'egg-log-buffer-push-head-to-local + :visible '(egg-ref-at-point) + :enable '(not (egg-remote-at-point)))) + (define-key map [upload] (list 'menu-item "Push Ref to Remote" + 'egg-log-buffer-push-to-remote + :visible '(egg-ref-at-point) + :enable '(not (egg-remote-at-point)))) + (define-key map [update] (list 'menu-item "Push to Another Local Branch" + 'egg-log-buffer-push-to-local + :visible '(egg-ref-at-point))) + (define-key map [sp5] '("--")) + (define-key map [irebase] (list 'menu-item "Rebase HEAD interratively" + 'egg-log-buffer-rebase + :visible '(egg-commit-at-point) + :enable '(egg-log-buffer-get-marked-alist))) + (define-key map [unmark] (list 'menu-item "Unmark for interractive Rebase " + 'egg-log-buffer-unmark + :visible '(egg-commit-at-point))) + (define-key map [edit] (list 'menu-item "Mark for Editing in upcoming interractive Rebase " + 'egg-log-buffer-mark-edit + :visible '(egg-commit-at-point))) + (define-key map [squash] (list 'menu-item "Mark to be Squashed in upcoming interractive Rebase " + 'egg-log-buffer-mark-squash + :visible '(egg-commit-at-point))) + (define-key map [pick] (list 'menu-item "Mark to be Picked in upcoming interractive Rebase " + 'egg-log-buffer-mark-pick + :visible '(egg-commit-at-point))) + (define-key map [base] (list 'menu-item "Mark as Base Commit " + 'egg-log-buffer-mark + :visible '(egg-commit-at-point))) + (define-key map [sp4] '("--")) + (define-key map [rebase] (list 'menu-item "Rebase HEAD" + 'egg-log-buffer-rebase + :visible '(egg-commit-at-point))) + (define-key map [merge] (list 'menu-item "Merge to HEAD" + 'egg-log-buffer-merge + :visible '(egg-commit-at-point))) + (define-key map [sp3] '("--")) + (define-key map [rh-16] (list 'menu-item "Anchor HEAD (update INDEX and Workdir)" + 'egg-log-commit-line-menu-attach-head-index-wdir + :visible '(egg-commit-at-point))) + (define-key map [rh-4] (list 'menu-item "Anchor HEAD (update INDEX)" + 'egg-log-commit-line-menu-attach-head-index + :visible '(egg-commit-at-point))) + (define-key map [rh-0] (list 'menu-item "Anchor HEAD" + 'egg-log-buffer-attach-head + :visible '(egg-commit-at-point))) + (define-key map [sp2] '("--")) + (define-key map [reflog] (list 'menu-item "Show Ref History (Reflog)" + 'egg-log-buffer-reflog-ref + :visible '(egg-ref-at-point))) + (define-key map [rm-ref] (list 'menu-item "Remove Ref " + 'egg-log-buffer-rm-ref + :visible '(egg-ref-at-point))) + (define-key map [cb] (list 'menu-item "Create New Branch" + 'egg-log-buffer-create-new-branch + :visible '(egg-commit-at-point))) + (define-key map [co-dh] (list 'menu-item "Detach HEAD and Checkout" + 'egg-log-buffer-checkout-commit + :visible '(egg-commit-at-point))) + (define-key map [sp1] '("--")) + (define-key map [sb] (list 'menu-item "Start New Branch" + 'egg-log-buffer-start-new-branch + :visible '(egg-commit-at-point))) + (define-key map [co] (list 'menu-item "Checkout Branch" + 'egg-log-buffer-checkout-commit + :visible '(egg-head-at-point))) + (define-key map [tag] (list 'menu-item "Tag (Lightweight)" + 'egg-log-buffer-tag-commit + :visible '(egg-commit-at-point))) + (define-key map [atag] (list 'menu-item "Tag (Annotated)" + 'egg-log-buffer-atag-commit + :visible '(egg-commit-at-point))) + map)) + +(defconst egg-log-buffer-commit-line-menu (egg-log-make-commit-line-menu)) +(defconst egg-log-buffer-local-ref-menu (egg-log-make-commit-line-menu)) +(defconst egg-log-buffer-remote-ref-menu (egg-log-make-commit-line-menu)) +(defconst egg-log-buffer-remote-site-menu (egg-log-make-commit-line-menu)) +(defconst egg-log-buffer-mode-commit-menu (egg-log-make-commit-line-menu)) + +(defun egg-log-commit-line-menu-heading (pos &optional prefix) + (let ((ref (get-text-property pos :ref)) + (references (get-text-property pos :references)) + (commit (get-text-property pos :commit)) + (prefix (or prefix "(Git/Egg)"))) + (cond ((consp ref) + (format "%s %s: %s" prefix + (cond ((eq (cdr ref) :head) "Branch") + ((eq (cdr ref) :remote) "Remote") + ((eq (cdr ref) :tag) "Tag")) + (car ref))) + ((consp references) + (concat "Ref: " prefix (car (last references)))) + ((stringp commit) + (concat prefix " Commit: " + (file-name-nondirectory + (egg-name-rev commit)))) + (t "No Commit Here")))) + +(defun egg-log-commit-mouse-menu-heading (&optional prefix) + (let* ((event last-command-event) + (window (posn-window (event-end event))) + (buffer (and window (window-buffer window))) + (pos (posn-point (event-end event)))) + (egg-log-commit-line-menu-heading pos prefix))) + +(defun egg-log-popup-commit-line-menu-1 (event generic-menu) + (let* ((window (posn-window (event-end event))) + (buffer (and window (window-buffer window))) + (pos (posn-point (event-end event))) + menu keys cmd) + (when (bufferp buffer) + (save-excursion + (with-temp-buffer buffer) + (goto-char pos) + (setq menu + (nconc (list 'keymap + (egg-log-commit-line-menu-heading pos)) + (cdr generic-menu))) + (setq keys (progn + (force-mode-line-update) + (x-popup-menu event menu))) + (setq cmd (and keys (lookup-key menu (apply 'vector keys)))) + (when (and cmd (commandp cmd)) + (call-interactively cmd)))))) + +(defun egg-log-popup-local-ref-menu (event) + (interactive "e") + (egg-log-popup-commit-line-menu-1 event egg-log-buffer-local-ref-menu)) + +(defun egg-log-popup-remote-ref-menu (event) + (interactive "e") + (egg-log-popup-commit-line-menu-1 event egg-log-buffer-remote-ref-menu)) + +(defun egg-log-popup-remote-site-menu (event) + (interactive "e") + (egg-log-popup-commit-line-menu-1 event egg-log-buffer-remote-site-menu)) + +(defun egg-log-popup-commit-line-menu (event) + (interactive "e") + (egg-log-popup-commit-line-menu-1 event egg-log-buffer-commit-line-menu)) + +;; (define-key egg-log-local-ref-map [C-down-mouse-2] 'egg-popup-log-local-ref-menu) +;; (define-key egg-log-local-ref-map [C-mouse-2] 'egg-popup-log-local-ref-menu) + +(defconst egg-log-buffer-menu (make-sparse-keymap "Egg (Git)")) + +(define-key egg-log-buffer-mode-map + [menu-bar egg-log-buffer-mode] (cons "Egg (Git)" egg-log-buffer-menu)) + +(let ((menu egg-log-buffer-menu)) + (define-key menu [quit] '(menu-item "Close History View" egg-quit-buffer)) + (define-key menu [refresh] '(menu-item "Refresh History View" egg-buffer-cmd-refresh)) + (define-key menu [pickaxe] '(menu-item "Search History for Changes" + egg-search-changes)) + (define-key menu [goto] '(menu-item "Locate Line in File" + egg-log-hunk-cmd-visit-file-other-window + :enable (egg-hunk-at-point))) + (define-key menu [sp3] '("--")) + (define-key menu [commit] (list 'menu-item + '(egg-log-commit-mouse-menu-heading "Operations on ") + egg-log-buffer-mode-commit-menu + :visible '(egg-commit-at-point))) + (define-key menu [sp1] '("--")) + (define-key menu [hs] '(menu-item "Hide/Show Details" + egg-section-cmd-toggle-hide-show + :enable (egg-navigation-at-point))) + (define-key menu [hs-sub] '(menu-item "Hide/Show Details of Subsections" + egg-section-cmd-toggle-hide-show-children + :enable (egg-navigation-at-point))) + (define-key menu [prev] '(menu-item "Goto Previous Ref" egg-log-buffer-prev-ref)) + (define-key menu [next] '(menu-item "Goto Next Ref" egg-log-buffer-next-ref))) + +(defconst egg-log-buffer-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) + "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-next-ref]:next thing " + "\\[egg-log-buffer-prev-ref]:previous thing " + "\\[egg-search-changes]:search history " + "\\[egg-status]:show repo's status " + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n") + (egg-text "Extra Key Bindings for a Commit line:" 'egg-help-header-2) + "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-insert-commit]:load details " + "\\[egg-section-cmd-toggle-hide-show]:hide/show details " + "\\[egg-section-cmd-toggle-hide-show-children]:hide sub-blocks " + "\\[egg-log-buffer-checkout-commit]:checkout " + "\\[egg-log-buffer-start-new-branch]:start new branch\n" + "\\[egg-log-buffer-attach-head]:anchor HEAD " + "\\[egg-log-buffer-tag-commit]:new tag " + "\\[egg-log-buffer-atag-commit]:new annotated tag " + "\\[egg-log-buffer-create-new-branch]:create branch " + "\\[egg-log-buffer-diff-revs]:diff vs HEAD (or BASE)\n" + "\\[egg-log-buffer-merge]:merge to HEAD " + "\\[egg-log-buffer-rebase]:rebase HEAD " + "\\[egg-log-buffer-rebase-interactive]:rebase HEAD interactively" + "\n" + ) + (egg-text "Extra Key Bindings to prepare a (interactive) rebase:" 'egg-help-header-2) + "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-mark]:mark as BASE " + "\\[egg-log-buffer-mark-pick]:mark as picked " + "\\[egg-log-buffer-mark-squash]:mark as squashed " + "\\[egg-log-buffer-mark-edit]:mark as edited " + "\\[egg-log-buffer-unmark]:unmark\n") + (egg-text "Extra Extra Key Bindings for a Ref:" 'egg-help-header-2) + "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-rm-ref]:delete ref " + "\\[egg-log-buffer-push-to-local]:update another local ref " + "\\[egg-log-buffer-push-to-remote]:upload to remote " + "\\[egg-log-buffer-push-head-to-local]:download\n") + (egg-text "Extra Key Bindings for a Diff Block:" 'egg-help-header-2) + "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-diff-cmd-visit-file-other-window]:visit version/line\n") + (egg-text "References:" 'egg-help-header-2) "\n" + (egg-text "local-branch" 'egg-branch-mono) " " + (egg-text "lightweight-tag" 'egg-tag-mono) " " + (egg-text "annotated-tag" 'egg-an-tag-mono) " " + (egg-text "remote/" 'egg-remote-mono) + (egg-text "branch" 'egg-branch-mono) " " + (egg-text " HEAD " 'egg-log-HEAD) " " + "\n")) + +(defun egg-log-buffer-diff-revs (pos) + "Compare HEAD against the rev at POS." + (interactive "d") + (let* ((rev (egg-log-buffer-get-rev-at pos :symbolic)) + (mark (egg-log-buffer-find-first-mark ?*)) + (base (if mark (egg-log-buffer-get-rev-at mark :symbolic) "HEAD")) + buf) + (unless (and rev (stringp rev)) + (error "No commit here to compare against %s!" base)) + (when (string-equal rev base) + (error "It's pointless to compare %s vs %s!" rev base)) + (setq buf (egg-do-diff (egg-build-diff-info rev base))) + (pop-to-buffer buf t))) + +(defun egg-log (&optional all) + (interactive "P") + (let* ((egg-internal-current-state + (egg-repo-state (if (interactive-p) :error-if-not-git))) + (git-dir (egg-git-dir (interactive-p))) + (default-directory (file-name-directory git-dir)) + (buf (egg-get-log-buffer 'create)) + help) + (with-current-buffer buf + (when (memq :log egg-show-key-help-in-buffers) + (setq help egg-log-buffer-help-text)) + (set + (make-local-variable 'egg-internal-log-buffer-closure) + (if all + (list :description (concat + (egg-text "history scope: " 'egg-text-2) + (egg-text "all refs" 'egg-term)) + :closure (lambda () + (egg-log-buffer-insert-n-decorate-logs + 'egg-run-git-log-all))) + (list :description (concat + (egg-text "history scope: " 'egg-text-2) + (egg-text "HEAD" 'egg-term)) + :closure (lambda () + (egg-log-buffer-insert-n-decorate-logs + 'egg-run-git-log-HEAD))))) + (if help (plist-put egg-internal-log-buffer-closure :help help)) + (egg-log-buffer-redisplay buf 'init)) + (cond + (egg-switch-to-buffer (switch-to-buffer buf)) + (t (pop-to-buffer buf t))))) +;;;======================================================== +;;; file history +;;;======================================================== +(define-egg-buffer file-log "*%s-file-log@%s*" + (kill-all-local-variables) + (setq buffer-read-only t) + (setq major-mode 'egg-file-log-buffer-mode + mode-name "Egg-FileHistory" + mode-line-process "" + truncate-lines t) + (use-local-map egg-log-buffer-mode-map) + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-log-buffer-simple-redisplay) + (set (make-local-variable 'egg-log-buffer-comment-column) 0) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-file-log-buffer-mode-hook)) + +(defsubst egg-run-git-file-log-HEAD (file) + (egg-git-ok t "log" (format "--max-count=%d" egg-log-HEAD-max-len) + "--graph" "--topo-order" "--no-color" + "--pretty=oneline" "--decorate" "--" file)) + +(defsubst egg-run-git-file-log-all (file) + (egg-git-ok t "log" (format "--max-count=%d" egg-log-all-max-len) + "--graph" "--topo-order" "--no-color" + "--pretty=oneline" "--decorate" "--all" "--" file)) + +(defconst egg-log-commit-simple-map + (let ((map (make-sparse-keymap "Egg:FileLogCommit"))) + (set-keymap-parent map egg-log-commit-base-map) + (define-key map (kbd "RET") 'egg-log-locate-commit) + (define-key map (kbd "C-c C-c") 'egg-log-locate-commit) + map)) + +(defsubst egg-log-buffer-decorate-logs-simple (log-insert-func arg) + (let ((beg (point))) + (funcall log-insert-func arg) + (unless (= (char-before (point-max)) ?\n) + (goto-char (point-max)) + (insert ?\n)) + (goto-char beg) + (egg-decorate-log egg-log-commit-simple-map + egg-log-commit-simple-map + egg-log-commit-simple-map + egg-log-commit-simple-map))) + +(defun egg-log-buffer-simple-redisplay (buffer &optional init) + (with-current-buffer buffer + (egg-generic-display-logs egg-internal-log-buffer-closure init))) + +(defconst egg-file-log-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-next-ref]:next thing " + "\\[egg-log-buffer-prev-ref]:previous thing " + "\\[egg-status]:show repo's status " + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n" ) + (egg-text "Extra Key Bindings for a Commit line:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-locate-commit]:locate commit in history " + "\\[egg-log-buffer-insert-commit]:load details " + "\\[egg-section-cmd-toggle-hide-show]:hide/show details " + "\\[egg-section-cmd-toggle-hide-show-children]:hide sub-blocks\n" + "\\[egg-log-buffer-attach-head]:anchor HEAD " + "\\[egg-log-buffer-checkout-commit]:checkout " + "\\[egg-log-buffer-start-new-branch]:start new branch " + "\\[egg-log-buffer-create-new-branch]:create branch\n" + "\\[egg-log-buffer-tag-commit]:new tag " + "\\[egg-log-buffer-atag-commit]:new annotated tag\n" + ) + (egg-text "Extra Key Bindings for a Diff Block:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-diff-cmd-visit-file-other-window]:visit version/line\n") + )) + +(defun egg-file-log (file-name &optional all) + (interactive (list (buffer-file-name) current-prefix-arg)) + (unless (and file-name (file-exists-p file-name)) + (error "File does not exist: %s" file-name)) + (let ((buffer (egg-get-file-log-buffer 'create)) + (title (concat (egg-text "history of " 'egg-text-2) + (egg-text file-name 'egg-term))) + help) + (with-current-buffer buffer + (set + (make-local-variable 'egg-internal-log-buffer-closure) + (if all + (list :title title + :description (concat (egg-text "scope: " 'egg-text-2) + (egg-text "all refs" 'egg-branch-mono)) + :closure `(lambda () + (egg-log-buffer-decorate-logs-simple + #'egg-run-git-file-log-all ,file-name))) + (list :title title + :description (concat (egg-text "scope: " 'egg-text-2) + (egg-text "HEAD" 'egg-branch-mono)) + :closure `(lambda () + (egg-log-buffer-decorate-logs-simple + #'egg-run-git-file-log-HEAD ,file-name))))) + (when (memq :file-log egg-show-key-help-in-buffers) + (setq help egg-file-log-help-text)) + (if help (plist-put egg-internal-log-buffer-closure :help help))) + (egg-log-buffer-simple-redisplay buffer 'init) + (pop-to-buffer buffer t))) + +;;;======================================================== +;;; commit search +;;;======================================================== +(defconst egg-query:commit-commit-map + (let ((map (make-sparse-keymap "Egg:LogQueryCommit"))) + (set-keymap-parent map egg-hide-show-map) + (define-key map (kbd "SPC") 'egg-log-buffer-insert-commit) + (define-key map (kbd "o") 'egg-log-buffer-checkout-commit) + (define-key map (kbd "a") 'egg-log-buffer-attach-head) + (define-key map (kbd "RET") 'egg-log-locate-commit) + (define-key map (kbd "C-c C-c") 'egg-log-locate-commit) + map)) + +(defun egg-log-locate-commit (pos) + (interactive "d") + (let ((sha1 (get-text-property pos :commit)) + (buf (egg-get-log-buffer 'create))) + (with-current-buffer buf + (set (make-local-variable 'egg-internal-log-buffer-closure) + (list :description + (concat (egg-text "history scope: " 'egg-text-2) + (egg-text "HEAD" 'egg-term) + (egg-text " and " 'egg-text-2) + (egg-text sha1 'egg-term)) + :closure + (lambda () + (egg-log-buffer-insert-n-decorate-logs + `(lambda () + (egg-git-ok t "log" "--max-count=10000" "--graph" + "--topo-order" "--pretty=oneline" "--no-color" + "--decorate" "HEAD" sha1)))))) + (egg-log-buffer-redisplay buf) + (setq pos (point-min)) + (while (and pos + (not (equal (get-text-property pos :commit) sha1))) + (setq pos (next-single-property-change pos :commit)))) + (pop-to-buffer buf t) + (egg-log-buffer-goto-pos pos) + (recenter))) + +(defun egg-query:commit-buffer-rerun (buffer &optional init) + (interactive (list (current-buffer))) + (with-current-buffer buffer + (plist-put egg-internal-log-buffer-closure :title + (egg-text "History Search" 'egg-branch)) + (egg-generic-display-logs egg-internal-log-buffer-closure init))) + +(define-egg-buffer query:commit "*%s-query:commit@%s*" + (kill-all-local-variables) + (setq buffer-read-only t) + (setq major-mode 'egg-query:commit-buffer-mode + mode-name "Egg-Query:Commit" + mode-line-process "" + truncate-lines t) + (use-local-map egg-buffer-mode-map) + (set (make-local-variable 'egg-internal-log-buffer-closure) nil) + (set (make-local-variable 'egg-buffer-refresh-func) + 'egg-query:commit-buffer-rerun) + ;; re use log-buffer redrawing + (set (make-local-variable 'egg-log-buffer-comment-column) 0) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-query:commit-buffer-mode-hook)) + +(defun egg-insert-n-decorate-pickaxed-logs (string) + (let ((beg (point))) + (egg-git-ok t "log" "--pretty=oneline" "--decorate" "--no-color" + (concat "-S" string)) + (goto-char beg) + (egg-decorate-log egg-query:commit-commit-map + egg-query:commit-commit-map + egg-query:commit-commit-map + egg-query:commit-commit-map))) + +(defun egg-search-changes (string) + (interactive "ssearch history for changes containing: ") + (let* ((git-dir (egg-git-dir (interactive-p))) + (default-directory (file-name-directory git-dir)) + (buf (egg-get-query:commit-buffer 'create)) + (desc (concat (egg-text "Commits containing: " 'egg-text-2) + (egg-text string 'egg-term))) + (func `(lambda () + (egg-insert-n-decorate-pickaxed-logs ,string)))) + (with-current-buffer buf + (set (make-local-variable 'egg-internal-log-buffer-closure) + (list :description desc :closure func)) + (egg-query:commit-buffer-rerun buf 'init)) + (pop-to-buffer buf t))) +;;;======================================================== +;;; reflog +;;;======================================================== +(defsubst egg-run-reflog-branch (branch) + (egg-git-ok t "log" "-g" "--pretty=oneline" "--decorate" "--no-color" + (format "--max-count=%d" egg-log-HEAD-max-len) + branch)) + +(define-egg-buffer reflog "*%s-reflog@%s*" + (egg-file-log-buffer-mode) + (setq major-mode 'egg-reflog-buffer-mode + mode-name "Egg-RefLog") + (run-mode-hooks 'egg-reflog-buffer-mode-hook)) + +(defconst egg-reflog-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-buffer-next-ref]:next thing " + "\\[egg-log-buffer-prev-ref]:previous thing " + "\\[egg-status]:show repo's status " + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n" ) + (egg-text "Extra Key Bindings for a Commit line:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-locate-commit]:locate commit in history " + "\\[egg-log-buffer-insert-commit]:load details " + "\\[egg-section-cmd-toggle-hide-show]:hide/show details " + "\\[egg-section-cmd-toggle-hide-show-children]:hide sub-blocks\n" + "\\[egg-log-buffer-attach-head]:anchor HEAD " + "\\[egg-log-buffer-checkout-commit]:checkout " + "\\[egg-log-buffer-tag-commit]:new tag " + "\\[egg-log-buffer-atag-commit]:new annotated tag\n" + ) + (egg-text "Extra Key Bindings for a Diff Block:" egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-log-diff-cmd-visit-file-other-window]:visit version/line\n") + "\n" + )) + +(defun egg-reflog (branch) + (interactive (list (if current-prefix-arg + (egg-read-rev "show history of ref: " "HEAD") + "HEAD"))) + (unless branch (setq branch "HEAD")) + (let ((egg-internal-current-state (egg-repo-state :error-if-not-git)) + (buffer (egg-get-reflog-buffer 'create)) + (title (concat (egg-text "history of " 'egg-text-2) + (egg-text branch 'egg-branch))) + help) + (with-current-buffer buffer + (set + (make-local-variable 'egg-internal-log-buffer-closure) + (list :title title + :closure `(lambda () + (egg-log-buffer-decorate-logs-simple + #'egg-run-reflog-branch ,branch)))) + (when (memq :reflog egg-show-key-help-in-buffers) + (setq help egg-reflog-help-text)) + (if help (plist-put egg-internal-log-buffer-closure :help help))) + (egg-log-buffer-simple-redisplay buffer 'init) + (pop-to-buffer buffer t))) + +(defun egg-log-buffer-reflog-ref (pos) + (interactive "d") + (egg-reflog (car (get-text-property pos :ref)))) + +;;;======================================================== +;;; stash +;;;======================================================== +(defsubst egg-list-stash (&optional ignored) + (egg-git-ok t "stash" "list" "--pretty=oneline")) + +(define-egg-buffer stash "*%s-stash@%s*" + (egg-file-log-buffer-mode) + (use-local-map egg-stash-buffer-mode-map) + (setq major-mode 'egg-stash-buffer-mode + mode-name "Egg-Stash") + (run-mode-hooks 'egg-stash-buffer-mode-hook)) + +(defun egg-stash-buffer-do-insert-stash (pos) + (save-excursion + (let ((stash (get-text-property pos :stash)) + (nav (get-text-property pos :navigation)) + (inhibit-read-only t) + beg end) + (goto-char pos) + (goto-char (1+ (line-end-position))) + (setq beg (point)) + (unless (egg-git-ok t "stash" "show" "-p" + "--src-prefix=BASE:/" "--dst-prefix=WIP:/" + stash) + (error "error calling git stash show %s!" stash)) + (setq end (point)) + (egg-delimit-section :stash stash beg end (1- beg) nil nav) + (put-text-property beg end 'keymap egg-section-map) + (egg-decorate-diff-section :begin beg + :end end + :src-prefix "BASE:/" + :dst-prefix "WIP:/" + :diff-map egg-log-diff-map + :hunk-map egg-log-hunk-map) + (goto-char beg) + (setq end (next-single-property-change beg :diff)) +;;; (put-text-property beg (+ indent-column beg) 'face 'egg-diff-none) +;;; (put-text-property (+ indent-column beg) (line-end-position) +;;; 'face 'egg-text-2) + (forward-line 1) + (set-buffer-modified-p nil)))) + +(defun egg-stash-buffer-show (pos) + (interactive "d") + (let* ((next (next-single-property-change pos :diff)) + (stash (and next (get-text-property next :stash)))) + (unless (equal (get-text-property pos :stash) stash) + (egg-stash-buffer-do-insert-stash pos)))) + +(defun egg-stash-buffer-pop (&optional no-confirm) + (interactive "P") + (unless (egg-wdir-clean) + (egg-status) + (error "Cannot aplly stash on dirty work-dir")) + (when (or no-confirm + (y-or-n-p "pop and apply last WIP to repo? ")) + (when (egg-do-pop-stash) + (message "GIT-STASH> successfully popped and applied last WIP") + (egg-status)))) + +(defun egg-stash-buffer-apply (pos &optional no-confirm) + (interactive "dP") + (unless (egg-wdir-clean) + (egg-status) + (error "Cannot aplly stash on dirty work-dir")) + (let ((stash (get-text-property pos :stash))) + (when (and stash (stringp stash) + (or no-confirm + (y-or-n-p (format "apply WIP %s to repo? " stash)))) + (when (egg-do-apply-stash stash) + (message "GIT-STASH> successfully applied %s" stash) + (egg-status))))) + +(defun egg-buffer-stash-wip (msg) + (interactive "sshort description of this work-in-progress: ") + (egg-do-stash-wip msg) + (egg-stash)) + +(defconst egg-stash-buffer-mode-map + (let ((map (make-sparse-keymap "Egg:StashBuffer"))) + (set-keymap-parent map egg-buffer-mode-map) + (define-key map "n" 'egg-stash-buffer-next-stash) + (define-key map "s" 'egg-status) + (define-key map "p" 'egg-stash-buffer-prev-stash) + (define-key map (kbd "RET") 'egg-stash-buffer-pop) + (define-key map (kbd "o") 'egg-stash-buffer-pop) + (define-key map "l" 'egg-log) + + map)) + +(defconst egg-stash-map + (let ((map (make-sparse-keymap "Egg:Stash"))) + (set-keymap-parent map egg-hide-show-map) + (define-key map (kbd "SPC") 'egg-stash-buffer-show) + (define-key map (kbd "RET") 'egg-stash-buffer-apply) + (define-key map "a" 'egg-stash-buffer-apply) + (define-key map (kbd "DEL") 'egg-stash-buffer-drop) + (define-key map "x" 'egg-stash-buffer-drop) + (define-key map "X" 'egg-stash-buffer-clear) + map)) + +(defun egg-stash-buffer-next-stash () + "Move to the next stash." + (interactive) + (egg-buffer-cmd-next-block :stash)) + +(defun egg-stash-buffer-prev-stash () + "Move to the previous stash." + (interactive) + (egg-buffer-cmd-prev-block :stash)) + + +(defconst egg-stash-help-text + (concat + (egg-text "Common Key Bindings:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-stash-buffer-next-stash]:next stash " + "\\[egg-stash-buffer-prev-stash]:previous stash " + "\\[egg-status]:show repo's status " + "\\[egg-buffer-cmd-refresh]:redisplay " + "\\[egg-quit-buffer]:quit\n" ) + (egg-text "Extra Key Bindings for a Stash line:" 'egg-help-header-2) "\n" + (egg-pretty-help-text + "\\" + "\\[egg-stash-buffer-apply]:apply\n" + "\\[egg-stash-buffer-show]:load details\n" + "\\[egg-stash-buffer-drop]:delete stash\n" + "\\[egg-stash-buffer-pop]:pop and apply stash\n" + "\\[egg-stash-buffer-clear]:delete all\n" + ) + "\n" + )) + +(defun egg-decorate-stash-list (&optional line-map) + (let ((start (point)) stash-beg stash-end beg end msg-beg msg-end + name msg) + (save-excursion + (while (re-search-forward "^\\(stash@{[0-9]+}\\): +\\(.+\\)$" nil t) + (setq beg (match-beginning 0) + stash-end (match-end 1) + msg-beg (match-beginning 2) + end (match-end 0)) + + (setq name (buffer-substring-no-properties beg stash-end) + msg (buffer-substring-no-properties msg-beg end)) + + ;; entire line + (add-text-properties beg (1+ end) + (list :navigation name + :stash name + 'keymap line-map)) + + ;; comment + (put-text-property beg stash-end 'face 'egg-stash-mono) + (put-text-property msg-beg end 'face 'egg-text-2))))) + +(defsubst egg-stash-buffer-decorate-stash-list () + (let ((beg (point))) + (egg-list-stash) + (unless (= (char-before (point-max)) ?\n) + (goto-char (point-max)) + (insert ?\n)) + (goto-char beg) + (egg-decorate-stash-list egg-stash-map))) + +(defun egg-stash () + (interactive) + (let ((egg-internal-current-state (egg-repo-state :error-if-not-git)) + (buffer (egg-get-stash-buffer 'create)) + title help) + (setq title (concat (egg-text "Stash(es)" 'egg-branch))) + (with-current-buffer buffer + (set + (make-local-variable 'egg-internal-log-buffer-closure) + (list :title title + :closure #'egg-stash-buffer-decorate-stash-list)) + (when (memq :stash egg-show-key-help-in-buffers) + (setq help egg-stash-help-text)) + (if help (plist-put egg-internal-log-buffer-closure :help help))) + (egg-log-buffer-simple-redisplay buffer 'init) + (pop-to-buffer buffer t))) + + +;;;======================================================== +;;; annotated tag +;;;======================================================== +(defvar egg-internal-annotated-tag-name nil) +(defvar egg-internal-annotated-tag-target nil) + +(defun egg-tag-msg-create-tag () + (let (output) + (setq output + (egg-sync-git-region egg-log-msg-text-beg egg-log-msg-text-end + "tag" "-a" "-F" "-" + egg-internal-annotated-tag-name + egg-internal-annotated-tag-target)) + (when output + (egg-show-git-output output -1 "GIT-ANNOTATED-TAG") + (egg-run-buffers-update-hook)))) + +(define-egg-buffer tag:msg "*%s-tag:msg@%s*" + (egg-log-msg-mode) + (setq major-mode 'egg-tag:msg-buffer-mode + mode-name "Egg-Tag:Msg" + mode-line-process "") + (make-local-variable 'egg-internal-annotated-tag-name) + (setq buffer-invisibility-spec nil) + (run-mode-hooks 'egg-tag:msg-mode-hook)) + + +(defun egg-create-annotated-tag (name commit-1) + (let* ((git-dir (egg-git-dir)) + (default-directory (file-name-directory git-dir)) + (buf (egg-get-tag:msg-buffer 'create)) + (commit (egg-git-to-string "rev-parse" "--verify" commit-1)) + (pretty (egg-describe-rev commit)) + (inhibit-read-only inhibit-read-only)) + (or commit (error "Bad commit: %s" commit-1)) + (pop-to-buffer buf t) + (setq inhibit-read-only t) + (erase-buffer) + (set (make-local-variable 'egg-log-msg-action) + 'egg-tag-msg-create-tag) + (set (make-local-variable 'egg-internal-annotated-tag-name) name) + (set (make-local-variable 'egg-internal-annotated-tag-target) commit) + (insert (egg-text "Create Annotated Tag" 'egg-text-2) " " + (egg-text name 'egg-branch) "\n\n" + (egg-text "on commit:" 'egg-text-2) " " + (egg-text commit 'font-lock-string-face) "\n" + (egg-text "aka:" 'egg-text-2) " " + (egg-text pretty 'font-lock-string-face) "\n" + (egg-text "Repository: " 'egg-text-2) + (egg-text git-dir 'font-lock-constant-face) "\n" + (egg-text "----------------- Tag Message (type C-c C-c when done) ---------------" + 'font-lock-comment-face)) + (put-text-property (point-min) (point) 'read-only t) + (put-text-property (point-min) (point) 'rear-sticky nil) + (insert "\n") + (set (make-local-variable 'egg-log-msg-text-beg) (point-marker)) + (set-marker-insertion-type egg-log-msg-text-beg nil) + (set (make-local-variable 'egg-log-msg-text-end) (point-marker)) + (set-marker-insertion-type egg-log-msg-text-end t))) +;;;======================================================== +;;; minor-mode +;;;======================================================== +(defun egg-file-toggle-blame-mode (save) + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (when (and (buffer-modified-p) + (or save + (y-or-n-p (format "save %s first? " (buffer-file-name))))) + (save-buffer)) + (let (blame-was-on buffer-was-readonly) + (mapc (lambda (ov) + (when (overlay-get ov :blame) + (setq buffer-was-readonly (plist-get (overlay-get ov :blame) + :buffer-read-only)) + (setq blame-was-on t))) + (overlays-at (point))) + (if blame-was-on + (progn (egg-file-buffer-blame-off (current-buffer)) + (set-buffer-modified-p nil) + (setq buffer-read-only buffer-was-readonly)) + (egg-file-buffer-blame-on (current-buffer) + :buffer-read-only buffer-read-only) + (set-buffer-modified-p nil) + (setq buffer-read-only t)))) + +(defun egg-file-diff (&optional ask) + "Diff the current file in another window." + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let ((git-file (egg-buf-git-name)) + (src-rev (and ask (egg-read-rev "diff against: " "HEAD"))) + buf) + (setq buf (egg-do-diff (egg-build-diff-info src-rev nil git-file))) + (pop-to-buffer buf t))) + +(defun egg-file-checkout-other-version (&optional no-confirm) + "Checkout HEAD's version of the current file. +if CONFIRM-P was not null, then ask for confirmation if the +current file contains unstaged changes." + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let* ((file (buffer-file-name)) + (file-modified (not (egg-file-committed (buffer-file-name)))) + rev) + (when file-modified + (unless (y-or-n-p (format "ignored uncommitted changes in %s? " file)) + (error "File %s contains uncommitted changes!" file))) + (setq rev (egg-read-rev (format "checkout %s version: " file) "HEAD")) + (when (egg-sync-do-file file egg-git-command nil nil + (list "checkout" rev "--" file)) + (revert-buffer t t t)))) + +(defun egg-file-cancel-modifications (&optional no-confirm) + "Checkout INDEX's version of the current file. +if CONFIRM-P was not null, then ask for confirmation if the +current file contains unstaged changes." + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let* ((file (buffer-file-name)) + (file-modified (not (egg-file-updated (buffer-file-name)))) + rev) + (when (and file-modified (not no-confirm)) + (unless (y-or-n-p (format "ignored unstaged changes in %s? " file)) + (error "File %s contains unstaged changes!" file))) + (when (egg-sync-do-file file egg-git-command nil nil + (list "checkout" "--" file)) + (revert-buffer t t t)))) + +(defun egg-start-new-branch () + (interactive) + (egg-do-create-branch nil 'checkout "start new branch with name: ")) + +(defun egg-file-get-other-version (file &optional rev prompt same-mode name) + (let* ((mode (assoc-default file auto-mode-alist 'string-match)) + (git-dir (egg-git-dir)) + (lbranch (egg-current-branch)) + (rbranch (and git-dir (or (egg-tracking-target lbranch) + rev ":0"))) + (prompt (or prompt (format "%s's version: " file))) + (rev (or rev (egg-read-rev prompt rbranch))) + (canon-name (egg-file-git-name file)) + (git-name (concat rev ":" canon-name)) + (buf (get-buffer-create (concat "*" (or name git-name) "*")))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + (unless (= (call-process egg-git-command nil buf nil "show" + git-name) + 0) + (error "Failed to get %s's version: %s" file rev)) + (when (and (functionp mode) same-mode) + (funcall mode)) + (set-buffer-modified-p nil) + (setq buffer-read-only t))) + buf)) + +(defun egg-file-version-other-window (&optional ask) + "Show other version of the current file in another window." + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let ((buf (egg-file-get-other-version + (buffer-file-name) (if ask nil ":0") + (format "show %s's version:" (buffer-file-name)) + t))) + (unless (bufferp buf) + (error "Oops! can't get %s older version" (buffer-file-name))) + (pop-to-buffer buf t))) + +(defun egg-file-ediff (&optional ask-for-dst) + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let* ((file buffer-file-name) + (dst-buf (if ask-for-dst + (egg-file-get-other-version + (buffer-file-name) nil + (format "(ediff) %s's newer version: " file) + t) + (current-buffer))) + (src-buf (egg-file-get-other-version + (buffer-file-name) + nil + (format "(ediff) %s's older version: " file) + t))) + (unless (and (bufferp dst-buf) (bufferp src-buf)) + (error "Ooops!")) + (ediff-buffers dst-buf src-buf))) + +(defun egg-resolve-merge-with-ediff (&optional what) + (interactive "P") + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let* ((file buffer-file-name) + (short-file (file-name-nondirectory file)) + (ours (egg-file-get-other-version file ":2" nil t (concat "our:" short-file))) + (theirs (egg-file-get-other-version file ":3" nil t (concat "their:" short-file)))) + (unless (and (bufferp ours) (bufferp theirs)) + (error "Ooops!")) + (ediff-buffers3 theirs ours (current-buffer)))) + +(defun egg-file-do-ediff (closer-rev closer-rev-name &optional further-rev further-rev-name ediff2) + (unless (buffer-file-name) + (error "Current buffer has no associated file!")) + (let* ((file buffer-file-name) + (short-file (file-name-nondirectory file)) + (closer-name (concat (or closer-rev-name closer-rev) + ":" short-file)) + (this (egg-file-get-other-version file closer-rev nil t closer-name)) + (further-name (and further-rev + (concat (or further-rev-name further-rev) + ":" short-file))) + (that (and further-rev + (egg-file-get-other-version file further-rev nil t further-name)))) + (unless (bufferp this) (error "Ooops!")) + (unless (or (null further-rev) (bufferp that)) (error "Ooops!")) + (if (bufferp that) + (if ediff2 + (ediff-buffers that this) + (ediff-buffers3 that this (current-buffer))) + (ediff-buffers this (current-buffer))))) + +(defconst egg-key-action-alist + '((?m :merge-file "[m]erge current file" "Resolve merge conflict(s) in current file.") + (?f :stage-file "stage current [f]ile" "Stage current file's changes") + (?s :status "show repo's [s]tatus" "Browse the current status of the repo" ) + (?a :stage-all "stage [a]ll files" "Stage all current changes inside this repo.") + (?r :rebase-continue "continue [r]rebase" "Continue with the current rebase session.") + (?d :diff-file "[d]iff current file" "Compare the current file against the staged snapshot.") + (?c :commit "[c]ommit staged changes" "Proceed to commit current staged changes onto HEAD.") + (?y :sync "s[y]nc" "Synchronize branches and repos (push/fetch).") + (?? :more-options "[?] more options" nil) + (?b :new-branch "start new [b]ranch" "Create and switch to a new branch starting from HEAD.") + (?q :quit "[q] quit" nil))) + +(defconst egg-action-function-alist + '((:merge-file . egg-resolve-merge-with-ediff) + (:stage-file . egg-file-stage-current-file) + (:status . egg-status) + (:stage-all . egg-stage-all-files) + (:rebase-continue . egg-buffer-rebase-continue) + (:diff-file . egg-file-diff) + (:commit . egg-commit-log-edit) + (:sync . egg-log) + (:new-branch . egg-start-new-branch) + (:quit . (lambda () (interactive) (message "do nothing now! later.") (ding) nil)))) + +(defconst egg-action-menu-name-alist + '((:merge-file . "Resolve File's Merge Conflicts using Ediff") + (:stage-file . "Stage File's Modifications") + (:status . "View Project Status") + (:stage-all . "Stage All Project's Modifications") + (:rebase-continue . "Continue Rebase Session") + (:diff-file . "Show File's Modifications (Diff)") + (:commit . "Commit Staged Changes") + (:sync . "Show Project History") + (:new-branch . "Start a New Branch"))) + +(defconst egg-electrict-select-action-buffer + (get-buffer-create "*Egg:Select Action*")) + +(defun egg-select-action-run () + (interactive) + (let (action) + (save-excursion + (with-current-buffer egg-electrict-select-action-buffer + (beginning-of-line) + (when (boundp 'egg-electric-in-progress-p) + (setq action (get-text-property (point) :action)) + (if action + (throw 'egg-select-action action) + (ding))))))) + +(defun egg-select-action-quit () + (interactive) + (let (action) + (save-excursion + (with-current-buffer egg-electrict-select-action-buffer + (beginning-of-line) + (when (boundp 'egg-electric-in-progress-p) + (throw 'egg-select-action nil)))))) + +(defconst egg-electric-select-action-map + (let ((map (make-sparse-keymap "Egg:SelectAction"))) + (define-key map "q" 'egg-select-action-quit) + (define-key map (kbd "RET") 'egg-select-action-run) + (define-key map (kbd "SPC") 'egg-select-action-run) + (define-key map (kbd "C-l") 'recenter) + map)) + +(defun egg-electric-select-action (default banner &optional alternatives) + (let ((egg-electric-in-progress-p t) + (old-buffer (current-buffer)) + (buf egg-electrict-select-action-buffer) + (action-alist + (delq nil (mapcar (lambda (entry) + (if (and (cadddr entry) + (or (null alternatives) + (memq (cadr entry) alternatives))) + (cons (cadr entry) + (cadddr entry)))) + egg-key-action-alist))) + action default-entry beg) + (setq default-entry (assq default action-alist)) + (setq action-alist + (cons default-entry (remq default-entry action-alist))) + (unwind-protect + (setq action + (catch 'egg-select-action + (save-window-excursion + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (egg-text "Select Action\n" + 'egg-section-title)) + (insert (egg-text banner 'egg-text-1) "\n\n") + (insert (egg-text "select an action:" 'egg-text-1) + "\n\n") + (put-text-property (point-min) (point) + 'intangible t) + (setq beg (point)) + (insert + (mapconcat + (lambda (entry) + (egg-prop (concat "- " (cdr entry)) + :action (car entry) + 'face 'egg-electrict-choice)) + action-alist + "\n") + "\n") + (goto-char beg) + (set-buffer-modified-p nil) + (setq buffer-read-only t)) + (setq major-mode 'egg-select-action) + (setq mode-name "Egg-Select") + (use-local-map egg-electric-select-action-map)) + (Electric-pop-up-window egg-electrict-select-action-buffer) + (goto-char beg) + (Electric-command-loop 'egg-select-action + "select next action> ")))) + (bury-buffer buf)) + (when (and action (symbolp action)) + action))) + +(defsubst egg-guess-next-action (desc) + (cond ((memq :file-has-merged-conflict desc) :merge-file) + ((memq :file-is-modified desc) :stage-file) + ((memq :file-is-unmerged desc) :stage-file) + ((memq :wdir-has-merged-conflict desc) :status) + ((memq :wdir-has-unmerged-files desc) :stage-all) + ((memq :wdir-is-modified desc) :stage-all) + ((memq :rebase-in-progress desc) :rebase-continue) + ((memq :has-staged-changes desc) :commit) + (t :sync))) + +(defun egg-limit-alternative-actions (desc) + (let ((alternatives (mapcar 'car egg-action-function-alist))) + (unless (memq :file-has-merged-conflict desc) + (setq alternatives (delq :merge-file alternatives))) + (unless (memq :file-is-modified desc) + (setq alternatives (delq :diff-file (delq :stage-file alternatives)))) + (when (or (not (memq :wdir-is-modified desc)) + (memq :wdir-has-merged-conflict desc)) + (setq alternatives (delq :stage-all alternatives))) + (when (or (not (memq :rebase-in-progress desc)) + (memq :wdir-is-modified desc)) + (setq alternatives (delq :rebase-continue alternatives))) + (when (or (memq :wdir-is-modified desc) + (memq :rebase-in-progress desc) + (not (memq :has-staged-changes desc))) + (setq alternatives (delq :commit alternatives))) + (when (or (memq :wdir-has-merged-conflict desc) + (memq :rebase-in-progress desc)) + (setq alternatives (delq :new-branch alternatives))) + (when (or (memq :wdir-is-modified desc) + (memq :has-staged-changes desc) + (memq :rebase-in-progress desc)) + (setq alternatives (delq :sync alternatives))) + alternatives)) + + + +(defun egg-describe-state (state) + (let* ((git-dir (plist-get state :gitdir)) + (current-file (buffer-file-name)) + (default-directory (file-name-directory git-dir)) + (file-git-name (and current-file (egg-file-git-name current-file))) + (unstaged-files (plist-get state :unstaged)) + (staged-files (plist-get state :staged)) + (unmerged-files (plist-get state :unmerged)) + desc dummy) + (when unstaged-files + (setq desc (cons :wdir-is-modified desc))) + + (when staged-files + (setq desc (cons :has-staged-changes desc))) + + (when unmerged-files + (setq desc (cons :wdir-has-unmerged-files desc))) + + (when (plist-get state :rebase-step) + (setq desc (cons :rebase-in-progress desc))) + + (when unstaged-files + (with-temp-buffer + (egg-git-ok t "diff") + (setq dummy (buffer-string)) + (save-match-data + (goto-char (point-min)) + (if (search-forward "\n++<<<<<<<" nil t) + (setq desc (cons :wdir-has-merged-conflict desc))))) + + (when (and file-git-name (member file-git-name unstaged-files)) + (setq desc (cons :file-is-modified desc)) + (with-temp-buffer + (egg-git-ok t "diff" file-git-name) + (setq dummy (buffer-string)) + (save-match-data + (goto-char (point-min)) + (if (search-forward "\n++<<<<<<<" nil t) + (setq desc (cons :file-has-merged-conflict desc))))) + (when (member file-git-name unmerged-files) + (setq desc (cons :file-is-unmerged desc))))) + desc)) + +(defsubst egg-build-key-prompt (prefix default alternatives) + (let ((action-desc-alist (mapcar 'cdr egg-key-action-alist))) + (concat prefix " default: " + (nth 1 (assq default action-desc-alist)) + ". alternatives: " + (mapconcat 'identity + (mapcar (lambda (action) + (nth 1 (assq action action-desc-alist))) + (remq default alternatives)) ", ")))) + +(defun egg-prompt-next-action (described-state) + (let ((default (egg-guess-next-action described-state)) + (limited-alternatives (egg-limit-alternative-actions described-state)) + banner key action alternatives) + (setq alternatives (list default :status :more-options)) + (while (null action) + (setq key (read-key-sequence + (egg-build-key-prompt "next action?" + default alternatives))) + (setq key (string-to-char key)) + (setq action + (if (memq key '(?\r ?\n ?\ )) + default + (cadr (assq key egg-key-action-alist)))) + (when (eq action :more-options) + (setq banner + (format "%s %s\n%s %s\nINDEX %s" + (buffer-file-name) + (cond ((memq :file-has-merged-conflict described-state) + "contains conflicting merge-changes") + ((memq :file-is-modified described-state) + "contains unstaged changes") + (t "is not modified")) + (file-name-directory (egg-git-dir)) + (cond ((memq :wdir-has-merged-conflict described-state) + "has files with conflicting merge changes") + ((memq :wdir-is-modified described-state) + "has files with unstaged changes") + (t "is clean")) + (cond ((memq :rebase-in-progress described-state) + "has unfinished rebase session") + ((memq :has-staged-changes described-state) + "contains staged changes ready to commit") + (t "is empty")))) + (setq action (egg-electric-select-action default banner limited-alternatives))) + (when (null action) + (ding))) + action)) + +(defun egg-next-action (&optional ask) + (interactive "P") + (save-some-buffers nil 'egg-is-in-git) + (let* ((state (egg-repo-state :unstaged :staged :error-if-not-git)) + (desc (egg-describe-state state)) + action default) + (setq action (if (or ask egg-confirm-next-action) + (egg-prompt-next-action desc) + (egg-guess-next-action desc))) + + (call-interactively (cdr (assq action egg-action-function-alist))))) + +(defun egg-file-next-action-menu-name () + (let* ((state (egg-repo-state :unstaged :staged :error-if-not-git)) + (desc (egg-describe-state state)) + (action (egg-guess-next-action desc))) + (concat "Next Action: " + (cdr (assq action egg-action-menu-name-alist))))) + +(defun egg-file-next-action-menu-binding (&optional ignored) + (let* ((state (egg-repo-state :unstaged :staged :error-if-not-git)) + (desc (egg-describe-state state)) + (action (egg-guess-next-action desc))) + (cdr (assq action egg-action-function-alist)))) + +(defvar egg-minor-mode nil) +(defvar egg-minor-mode-map (make-sparse-keymap "Egg")) +(defvar egg-file-cmd-map (make-sparse-keymap "Egg:File")) + +(defun egg-mode-key-prefix-set (var val) + (define-key egg-minor-mode-map (read-kbd-macro val) egg-file-cmd-map) + (custom-set-default var val)) + +(defun egg-file-log-pickaxe (string) + (interactive (list (read-string "search history for: " + (egg-string-at-point)))) + (egg-search-changes string)) + +(let ((map egg-file-cmd-map)) + (define-key map (kbd "a") 'egg-file-toggle-blame-mode) + (define-key map (kbd "b") 'egg-start-new-branch) + (define-key map (kbd "d") 'egg-status) + (define-key map (kbd "c") 'egg-commit-log-edit) + (define-key map (kbd "e") 'egg-file-ediff) + (define-key map (kbd "g") 'egg-grep) + (define-key map (kbd "i") 'egg-file-stage-current-file) + (define-key map (kbd "l") 'egg-log) + (define-key map (kbd "L") 'egg-reflog) + (define-key map (kbd "h") 'egg-file-log) + (define-key map (kbd "o") 'egg-file-checkout-other-version) + (define-key map (kbd "s") 'egg-status) + (define-key map (kbd "u") 'egg-file-cancel-modifications) + (define-key map (kbd "v") 'egg-next-action) + (define-key map (kbd "w") 'egg-commit-log-edit) + (define-key map (kbd "/") 'egg-file-log-pickaxe) + (define-key map (kbd "=") 'egg-file-diff) + (define-key map (kbd "~") 'egg-file-version-other-window)) + +(defconst egg-minor-mode-menu (make-sparse-keymap "Egg (Git)")) +(define-key egg-minor-mode-map [menu-bar egg-minor-mode-menu] + (cons "Egg (Git)" egg-minor-mode-menu)) + +(let ((menu egg-minor-mode-menu)) + (define-key menu [reflog] '(menu-item "View RefLog" egg-reflog)) + (define-key menu [log] '(menu-item "View Project History" egg-log)) + (define-key menu [status] '(menu-item "View Project Status" egg-status)) + (define-key menu [blame] '(menu-item "Toggle Blame Mode" egg-file-toggle-blame-mode)) + (define-key menu [sp3] '("--")) + (define-key menu [grep] '(menu-item "Search Project's Other Versions (grep)" egg-grep)) + (define-key menu [pickaxe] '(menu-item "Search File History" egg-file-log-pickaxe)) + (define-key menu [vother] '(menu-item "View File Other Version" egg-file-version-other-window)) + (define-key menu [filelog] '(menu-item "View File History" egg-file-log)) + (define-key menu [sp2] '("--")) + (define-key menu [cother] '(menu-item "Checkout File's Other Version" egg-file-checkout-other-version)) + (define-key menu [ediff] + '(menu-item "EDiff File (vs INDEX)" egg-file-ediff + :enable (not (egg-file-updated (buffer-file-name))))) + (define-key menu [diff] + '(menu-item "Diff File (vs INDEX)" egg-file-diff + :enable (not (egg-file-updated (buffer-file-name))))) + (define-key menu [sp1] '("--")) + (define-key menu [undo] + '(menu-item "Cancel Modifications (revert to INDEX)" egg-file-cancel-modifications + :enable (not (egg-file-updated (buffer-file-name))))) + (define-key menu [commit] + '(menu-item "Commit Staged Changes" egg-commit-log-edit + :enable (not (egg-file-index-empty (buffer-file-name))))) + (define-key menu [stage] + '(menu-item "Stage File's Modifications" egg-file-stage-current-file + :enable (not (egg-file-updated (buffer-file-name))))) + (define-key menu [sp0] '("--")) + (define-key menu [next] + '(menu-item (egg-file-next-action-menu-name) egg-next-action + :keys "\\[egg-next-action]" + :filter egg-file-next-action-menu-binding))) + +(defcustom egg-mode-key-prefix "C-x v" + "Prefix keystrokes for egg minor-mode commands." + :group 'egg + :type 'string + :set 'egg-mode-key-prefix-set) + +(defvar egg-minor-mode-name " Git") + +;;;###autoload +(defun egg-minor-mode (&optional arg) + "Turn-on egg-minor-mode which would enable key bindings for +egg in current buffer.\\ +\\[egg-start-new-branch] start a new branch from the current HEAD. +\\[egg-status] shows the repo's current status +\\[egg-commit-log-edit] start editing the commit message for the current staged changes. +\\[egg-file-stage-current-file] stage new changes of the current file +\\[egg-log] shows repo's history +\\[egg-file-checkout-other-version] checkout another version of the current file +\\[egg-file-cancel-modifications] delete unstaged modifications in the current file +\\[egg-next-action] perform the next logical action +\\[egg-file-diff] compare file with index or other commits +\\[egg-file-version-other-window] show other version of the current file. + +\\{egg-minor-mode-map} +" + (interactive "p") + (setq egg-minor-mode (if (null arg) + (not egg-minor-mode) + (> arg 0))) + (when egg-minor-mode + (if (boundp 'vc-mode) + (set 'vc-mode nil)) + (make-local-variable 'egg-minor-mode-name) + (setq egg-minor-mode-name + (intern (concat "egg-" (egg-git-dir) "-HEAD"))))) + +;;;###autoload +(defun egg-minor-mode-find-file-hook () + (when (egg-is-in-git) + (make-local-variable 'egg-minor-mode) + (egg-minor-mode 1))) + +(when (or + (string-match "\\`git version 1.6." + (shell-command-to-string + (concat egg-git-command " --version"))) + (string-match "\\`git version 1.7." + (shell-command-to-string + (concat egg-git-command " --version")))) + (or (assq 'egg-minor-mode minor-mode-alist) + (setq minor-mode-alist + (cons '(egg-minor-mode egg-minor-mode-name) minor-mode-alist))) + + (setcdr (or (assq 'egg-minor-mode minor-mode-map-alist) + (car (setq minor-mode-map-alist + (cons (list 'egg-minor-mode) + minor-mode-map-alist)))) + egg-minor-mode-map) + + (add-hook 'find-file-hook 'egg-git-dir) + (add-hook 'find-file-hook 'egg-minor-mode-find-file-hook)) + +;;;======================================================== +;;; tool-tip +;;;======================================================== +(defun egg-ref-at (pos &optional object) + (car (get-text-property pos :ref object))) + +(defun egg-ref-or-commit-at (pos &optional object) + (or (car (get-text-property pos :ref object)) + (get-text-property pos :commit object))) + +(defun egg-commit-at (pos &optional object) + (get-text-property pos :commit object)) + +(defun egg-rsite-at (pos &optional object) + (egg-rbranch-to-remote (car (get-text-property pos :ref object)))) + +(defun egg-delta-file-at (pos &optional object) + (car (get-text-property pos :diff object))) + +(defun egg-delta-hunk-at (pos &optional object) + (car (get-text-property pos :hunk object))) + +(defun egg-section-at (pos &optional object) + (let* ((sect-prop (get-text-property pos :sect-type object)) + (sect (and sect-prop (get-text-property pos sect-prop object)))) + (unless sect + (setq sect (egg-commit-at pos object))) + (if (consp sect) + (car sect) + sect))) + +(defun egg-file-name-at (pos &optional buffer) + (when (bufferp buffer) + (save-excursion + (with-current-buffer buffer + (goto-char pos) + (ffap-file-at-point))))) + +(defconst egg-cmd-help-text-fmt-alist + '((egg-log-buffer-push-to-local egg-ref-or-commit-at "update another branch with %s") + (egg-log-buffer-push egg-rsite-at "push branches to remote %s") + (egg-log-buffer-fetch egg-ref-at "(re)-fetch %s") + (egg-log-buffer-rm-ref egg-ref-at "remove %s") + (egg-log-buffer-reflog-ref egg-ref-at "show history (reflog) of %s") + (egg-log-buffer-unmark egg-commit-at "unmark %s for upcoming rebase") + (egg-log-buffer-mark-edit egg-commit-at "mark %s to be edited in upcoming rebase") + (egg-log-buffer-mark-squash egg-commit-at "mark %s to be squashed in upcoming rebase") + (egg-log-buffer-mark-pick egg-commit-at "mark %s to be picked in upcoming rebase") + (egg-log-buffer-mark egg-commit-at "mark %s as BASE") + (egg-log-buffer-rebase egg-commit-at "rebase HEAD to %s") + (egg-log-buffer-attach-head egg-ref-or-commit-at "anchor HEAD at %s") + (egg-log-buffer-atag-commit egg-commit-at "create new annotated-tag at %s") + (egg-log-buffer-tag-commit egg-commit-at "create new tag at %s") + (egg-log-buffer-checkout-commit egg-ref-or-commit-at "checkout %s") + (egg-log-buffer-start-new-branch egg-commit-at "start a new branch at %s") + (egg-log-buffer-create-new-branch egg-commit-at "create a new branch at %s") + (egg-log-buffer-insert-commit egg-commit-at "load %s's details") + (egg-section-cmd-toggle-hide-show-children egg-section-at "hide/show %s's children's details") + (egg-section-cmd-toggle-hide-show egg-section-at "hide/show %s's details") + (egg-log-buffer-merge egg-ref-or-commit-at "merge %s to HEAD") + (egg-buffer-cmd-navigate-next nil "next block") + (egg-buffer-cmd-navigate-prev nil "prev block") + (egg-diff-section-cmd-visit-file-other-window egg-section-at "open %s in other window") + (egg-diff-section-cmd-visit-file egg-section-at "open %s") + (egg-diff-section-cmd-ediff nil "view this delta in ediff") + (egg-staged-section-cmd-ediff3 egg-section-at "view %s changes in ediff3") + (egg-diff-section-cmd-unstage egg-section-at "unstage %s") + (egg-diff-section-cmd-undo egg-section-at "delete theses changes from %s") + (egg-unstaged-section-cmd-ediff egg-section-at "view this delta in ediff") + (egg-diff-section-cmd-stage egg-section-at "stage %s") + (egg-unmerged-section-cmd-ediff3 nil "view this conflict in ediff3") + (egg-find-file-at-point egg-file-name-at "open %s") + (egg-ignore-pattern-from-string-at-point egg-file-name-at "add a pattern matching %s to .gitignore file") + (egg-status-buffer-stage-untracked-file egg-file-name-at "add %s to this repo") + (egg-mouse-hide-show-cmd egg-section-at "hide/show %s's details") + (egg-status-popup-staged-diff-menu egg-section-at "popup menu for %s") + (egg-status-popup-unstaged-diff-menu egg-section-at "popup menu for %s") + (egg-buffer-rebase-abort nil "abort rebase session") + (egg-buffer-selective-rebase-skip nil "skip rebase session's current commit") + (egg-buffer-selective-rebase-continue nil "continue rebase session") + (egg-log-buffer-diff-revs egg-ref-or-commit-at "diff %s vs HEAD") + )) + +(defun egg-buffer-help-echo (window buffer pos) + (if (and (bufferp buffer) (number-or-marker-p pos)) + (let ((keymap (get-text-property pos 'keymap buffer)) + seen-list func-name-alist) + (when (keymapp keymap) + (mapconcat + (lambda (mapping) + (if (consp mapping) + (let* ((key (car mapping)) + (cmd (cdr mapping)) + (howto (assq cmd egg-cmd-help-text-fmt-alist)) + (func (nth 1 howto)) + (fmt (nth 2 howto)) + (key-str (format-kbd-macro (vector key))) + (name (or (cdr (assq func func-name-alist)) + (when (functionp func) + (cdar (setq func-name-alist + (cons (cons func + (funcall func pos buffer)) + func-name-alist))))))) + (when (and (not (memq key seen-list)) (stringp fmt)) + (if (and (stringp name) (= (length name) 40)) + (setq name (substring name 0 8))) + (add-to-list 'seen-list key) + (format "%s - %s\n" key-str (format fmt name)))) + "")) + keymap ""))))) + +;;;======================================================== +;;; auto-update +;;;======================================================== + +(defvar egg-auto-update nil) + +(defun egg-maybe-update-status () + "Pull up the status buffer for the current buffer if there is one." + (let ((bufname (egg-buf-git-name))) + (when (and egg-auto-update bufname) + (egg-status t) + (egg-goto-block-filename bufname)))) + +(add-hook 'after-save-hook 'egg-maybe-update-status) + +(defun egg-goto-block-filename (filename) + (interactive "sFilename: ") + (egg-goto-block-regexp (concat "\\(un\\)?staged-" filename))) + + +(defun egg-goto-block-regexp (nav-regexp) + "Takes `nav-regexp' as regexp and moves cursor there." + (let (nav-point) + (goto-char (point-min)) + (let (prev-point) + (while (not (eql prev-point (point))) + (setq prev-point (point)) + (egg-buffer-cmd-navigate-next) + (let ((prop-name (symbol-name (egg-navigation-at-point)))) + (if (string-match nav-regexp prop-name) + (setq nav-point (point) + prev-point (point)))))) + nav-point)) + +(run-hooks 'egg-load-hook) +(provide 'egg) diff --git a/egg.elc b/egg.elc new file mode 100644 index 0000000000000000000000000000000000000000..05d1107a1817665448c2f76fac255334606e4b92 GIT binary patch literal 279833 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 literal 0 HcmV?d00001 diff --git a/init.el b/init.el new file mode 100644 index 00000000..0d869e92 --- /dev/null +++ b/init.el @@ -0,0 +1,320 @@ +;; seting the load-path for load-library: +(setq load-path +(append +(list (expand-file-name "/usr/local/lib/xemacs/xemacs-packages/lisp/")) +(list (expand-file-name "/home/baron/.xemacs/")) +;; (expand-file-name "/usr/share/emacs/lisp/") +load-path)) + +;; Some general links regarding these configs: +;; +;; http://www.emacswiki.org/emacs/EmacsCrashCode +;; http://www.emacswiki.org/emacs/EmacsCrashTips +;; http://www.emacswiki.org/emacs/EmacsNiftyTricks + + +(require 'centered-cursor-mode) + +;; load template support +(require 'template) +(template-initialize) + +;; load org mode +;; See http://orgmode.org/worg/org-tutorials/orgtutorial_dto.html for details + +(require 'org-install) +(add-to-list 'auto-mode-alist '("\\.org$" . org-mode)) +(define-key global-map "\C-cl" 'org-store-link) +(define-key global-map "\C-ca" 'org-agenda) +(setq org-log-done t) +(setq org-agenda-files (list "~/org/emacs.org" + "~/org/work.org" + "~/org/private.org" + "~/org/it.org" + )) + +(define-key global-map "\C-ce" '(lambda () (interactive) (find-file "~/org/emacs.org"))) + +;; load git support +; (require 'egg) +(load-library "egg") + +(load-library "cfengine") +;; to enable mouse-wheel +(load-library "mwheel") +;; (load-library "todo-mode") +(load-library "tramp") +(setq default-tramp-method "sftp") +(mwheel-install) + +;; twitter http://www.twmode.sourceforge.net/ +(add-to-list 'load-path "~/.xemacs/xemacs-packages/lisp/twittering-mode-3.0.0") +(require 'twittering-mode) + +;; For Big Brother Database + +;; (require 'bbdb) +;; (bbdb-initialize) + + +;; For AucTex: + +(setq TeX-auto-save t) +(setq TeX-parse-self t) +(setq-default TeX-master nil) + +;; For Perl: + +;; load cperl-mode for perl files +(fset 'perl-mode 'cperl-mode) + +;; for auto-completion + +(require 'auto-complete-config) +(add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict") +(add-to-list 'ac-dictionary "~/.dict") +(ac-config-default) +(add-to-list 'ac-modes 'cfengine3-mode) +(add-to-list 'ac-modes 'dns-mode) + + +;; syntax-highlighting +(font-lock-mode) +(global-font-lock-mode 1) + +;; Display Line Number and Col Number in mode-line +(column-number-mode t) +(line-number-mode t) + +;; Display time / email in mode-line +(setq display-time-24hr-format t) +(display-time) + +;; No menubar +(menu-bar-mode -1) + +;; Specify printing format +(setq ps-paper-type 'a4) + +;; Set ispell dictionary +(setq ispell-dictionary "english") + +;; Set Shell for M-| command +(setq shell-file-name "/bin/bash") + +;; Set Shell used by TeX +(setq tex-shell-file-name "/bin/bash") + +;; Set grep command options +(setq grep-command "grep -i -nH -e ") + +;; Confirm quit +(setq confirm-kill-emacs 'yes-or-no-p) + +;; Quick file access with bar +;; (speedbar t) + +;; Ignore case when completing file names +(setq read-file-name-completion-ignore-case t) + +;; Highlight parenthesis pairs +(show-paren-mode 1) + +;; Blinking parenthesis +(setq blink-matching-paren-distance nil) + +;; Highlight text between parens +(setq show-paren-style 'expression) + +;; Use buffer nanme as frame title +(setq frame-title-format "%b - emacs") + +;; Completion in mini-buffer +(icomplete-mode t) + +;; Stack minibuffers +(setq enable-recursive-minibuffers t) + +;; RecentFiles http://www.emacswiki.org/emacs/RecentFiles +(require 'recentf) +(recentf-mode 1) +(setq recentf-max-menu-items 42) +(global-set-key "\C-c\ \C-r" 'recentf-open-files) + +;; Some nice functions +;;(blink-matching-paren 1) +;;(paren-activate) +(defun insert-date () +"Insert the current date" +(interactive) +(insert-string (format-time-string "%B %e, %Y"))) +(defun load-git-cfengine () + "Load config and tags file of git cfengine repo" +(interactive) (visit-tags-table "~/.cfengine_tags") +(interactive) (find-file "~/.cfagent/inputs/config.cf") +) + +;;(defun scpload (&rest args) +;;"scp copy from pottwal" +;; (shell-command ( scp andreas@pottwal: emacstmp/)) +;;) + +(defun eshell/ssh (&rest args) +"Secure shell" +(let ((cmd (eshell-flatten-and-stringify +(cons "ssh" args))) +(display-type (framep (selected-frame)))) +(cond +((and +(eq display-type 't) +(getenv "STY")) +(send-string-to-terminal (format "\033]83;screen %s\007" cmd))) +((eq display-type 'x) +(eshell-do-eval +(eshell-parse-command +(format "rxvt -e %s &" cmd))) +nil) +(t +(apply 'eshell-exec-visual (cons "ssh" args)))))) + +;;(move-overlay hl-line-overlay +;; (line-beginning-position) (1+ (line-end-position)) +;; (current-buffer))))) + +(set-face-background-pixmap 'default "/home/baron/.xemacs/xemacs-bg.xpm") + + +;; pos1: goto start of line, start of screen, start of buffer +;; end: goto end of line, end of screen, end of buffer + +(global-set-key '[(home)] 'chb-home) +(global-set-key '[(end)] 'chb-end) +;; +(defun chb-home () +(interactive) +(setq zmacs-region-stays t) +(if (not (bolp)) +(beginning-of-line) +(if (eq this-command last-command) +(cond + ((not (= (point) (window-start))) + (move-to-window-line 0) + (beginning-of-line)) + (t + (goto-char (point-min))))))) + +(defun chb-end () +(interactive) +(setq zmacs-region-stays t) +(if (not (eolp)) +(end-of-line) +(if (eq this-command last-command) +(cond + ((not (= (point) (save-excursion + (move-to-window-line -1) + (end-of-line) + (point)))) + (move-to-window-line -1) + (end-of-line)) + (t + (goto-char (point-max))))))) + + + + +;; safe files with #! in first line as user executable + +(add-hook `after-safe-hook + #'(lambda () + (and (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (save-match-data + (looking-at "^#!")))) + (not (file-executable-p buffer-file-name)) + (shell-command (concat "chmod u+x " buffer-file-name)) + (message + (concat "Saved as script: " buffer-file-name))))) + +;; +;; list of recently opened files +;; + +;; (load "recent-files") +;; (setq recent-files-dont-include +;; '("~$" "tmp/." "INBOX" ".bbdb" ".newsrc." )) + +;; (setq recent-files-non-permanent-submenu t) +;; (setq recent-files-commands-submenu t) +;; (setq recent-files-number-of-entries 30) +;; (recent-files-initialize) + +;; Make the F12 key toggle Whitespace mode on and off. Whitespace mode causes +;; all hard tabs to be highlighted. You can also configure it to highlight space characters +;; in a different color. There is also an untabify function to convert hard tabs to the +;; appropriate number of spaces, and a tabify function to convert groups of spaces to +;; hard tabs. +(global-set-key (kbd "") 'whitespace-mode) + + +;; (add-hook 'find-file-hooks 'fume-setup-buffer) +;; (add-hook 'Manual-mode-hook 'turn-on-fume-mode) + +;; (function-menu USE-MENUBAR RETURN-ONLY MENU-ITEM-FUNCTION) + +;;==================================================================== +;;The Following Code Will Enable Me To Use The "Fume" Package Which +;;Creates, On The Menubar, A "Functions" Menu Containing The List Of +;;All The Functions In The Buffer Being Currently Displayed. +;;==================================================================== +;; +;;Setq-Default Set The Default Value Of A Var. This Def. Val. Is Seen +;;In Buffers That *Don'T* Have Their Own Values For The Variable. + +;(require function-menu) +;(Define-Key Global-Map 'F8 'Function-Menu) +;(Add-Hook 'Find-File-Hooks 'Fume-Add-Menubar-Entry) +;(Define-Key Global-Map "\C-Cl" 'Fume-List-Functions) +;(Define-Key Global-Map "\C-Cg" 'Fume-Prompt-Function-Goto) +;(Define-Key Global-Map '(Shift Button3) 'Mouse-Function-Menu) +;(Define-Key Global-Map '(Meta Button1) 'Fume-Mouse-Function-Goto) + +;(Add-Hook +; 'Find-File-Hooks +; (Function +; (Lambda() +; (If (And (String-Match "Xemacs" Emacs-Version) +; (Boundp 'Emacs-Major-Version) +; (Or (= Emacs-Major-Version 20) +; (And +; (= Emacs-Major-Version 19) +; (>= Emacs-Minor-Version 13))) +; (Not (Eq Major-Mode 'Latex-Mode))) +; (Fume-Add-Menubar-Entry)) +; ))) + + +(define-key global-map "\C-ct" 'visit-tags-table) +(define-key global-map "\C-cf" 'tags-search) + +(define-key global-map "\C-c\C-c" 'centered-cursor-mode) + +(define-key global-map "\C-cc" 'load-git-cfengine) + +;; NUMBERIC KEYPAD. nice number pad conveniences as extra function keys + +;; (global-set-key (kbd "") 'ergoemacs-close-current-buffer) +;; (global-set-key (kbd "") 'ergoemacs-previous-user-buffer) +;; (global-set-key (kbd "") 'ergoemacs-next-user-buffer) + +;; (global-set-key (kbd "") 'ergoemacs-previous-emacs-buffer) +;; (global-set-key (kbd "") 'ergoemacs-next-emacs-buffer) + +;; (global-set-key (kbd "") 'other-window) +;; (global-set-key (kbd "") 'delete-window) +;; (global-set-key (kbd "") 'delete-other-windows) +;; (global-set-key (kbd "") 'split-window-vertically) +;; (global-set-key (kbd "") 'xah-open-file-at-cursor) + +;; (global-set-key (kbd "") 'isearch-forward) diff --git a/template.el b/template.el new file mode 100644 index 00000000..ea36c4b5 --- /dev/null +++ b/template.el @@ -0,0 +1,2609 @@ +;;; template.el --- use templates, decorate comments, auto-update buffers + +;; Copyright (C) 1995-2003 Free Software Foundation, Inc. +;; +;; Author: Christoph Wedler +;; Version: (see `template-version' below) +;; Keywords: template, comment decoration, auto-updating, data, tools +;; X-URL: http://emacs-template.sourceforge.net/ + +;; This program 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 program 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 this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;; When you create a new file with Emacs, package Template supplies an initial +;; buffer content via a template: a file with normal text and expansion +;; forms. There is a menu to easily create such templates. You can also use new +;; commands to decorate comments and update the buffer contents. + +;; The main difference between Template and other similar packages is that you +;; can define very flexible templates without having to learn Lisp or changing +;; your Emacs init file. This package does not help Lisp programmers to define +;; complex macros. + +;; For details, check or, if you +;; prefer the manual style, the documentation of the following commands and +;; variables: +;; +;; * for templates: \\[template-new-file], `template-auto-insert', +;; `template-derivation-alist', `template-default-expansion-alist' and +;; `template-definition-start', +;; * for comment decoration: \\[template-single-comment] and +;; \\[template-block-comment], `template-comment-specification-alist' +;; * for updating: \\[template-update-buffer], `template-auto-update', +;; `template-update-buffer-alist' and `template-header-regexp-alist'. + +;; Bug fixes, bug reports, improvements, and suggestions for the newest version +;; are strongly appreciated. + +;;; Installation: + +;; This file requires Emacs-20.2, XEmacs-20.2 or higher. + +;; Put this file into your load-path and the following into your ~/.emacs: +;; (require 'template) +;; (template-initialize) + +;; You might want to add another item to the "File" menu by (in XEmacs): +;; (add-menu-button '("File") +;; ["Insert and Expand Template..." +;; template-expand-template +;; :active (not buffer-read-only)] +;; "Insert File...") + +;; To customize, use `M-x customize-group RET template RET' or the customize +;; entry in menu Options. + +;;; Code: + +(provide 'template) +(require 'custom) + +;; General Emacs/XEmacs-compatibility compile-time macros +(eval-when-compile + (require 'cl) + (defmacro cond-emacs-xemacs (&rest args) + (cond-emacs-xemacs-macfn + args "`cond-emacs-xemacs' must return exactly one element")) + (defun cond-emacs-xemacs-macfn (args &optional msg) + (if (atom args) args + (and (eq (car args) :@) (null msg) ; (:@ ...spliced...) + (setq args (cdr args) + msg "(:@ ....) must return exactly one element")) + (let ((ignore (if (string-match "XEmacs" emacs-version) :EMACS :XEMACS)) + (mode :BOTH) code) + (while (consp args) + (if (memq (car args) '(:EMACS :XEMACS :BOTH)) (setq mode (pop args))) + (if (atom args) + (or args (error "Used selector %s without elements" mode)) + (or (eq ignore mode) + (push (cond-emacs-xemacs-macfn (car args)) code)) + (pop args))) + (cond (msg (if (or args (cdr code)) (error msg) (car code))) + ((or (null args) (eq ignore mode)) (nreverse code)) + (t (nconc (nreverse code) args)))))) + ;; Emacs/XEmacs-compatibility `defun': remove interactive "_" for Emacs, use + ;; existing functions when they are `fboundp', provide shortcuts if they are + ;; known to be defined in a specific Emacs branch (for short .elc) + (defmacro defunx (name arglist &rest definition) + (let ((xemacsp (string-match "XEmacs" emacs-version)) reuses first) + (while (memq (setq first (car definition)) + '(:try :emacs-and-try :xemacs-and-try + :emacs-only :xemacs-only)) + (if (memq first (if xemacsp + '(:xemacs-and-try :xemacs-only) + '(:emacs-and-try :emacs-only))) + (setq reuses (cadr definition) + definition nil) + (unless (memq first '(:emacs-only :xemacs-only)) + (push (cadr definition) reuses))) + (setq definition (cddr definition))) + (if (and reuses (symbolp reuses)) + `(defalias ',name ',reuses) + (let* ((docstring (if (stringp (car definition)) (pop definition))) + (spec (and (not xemacsp) + (eq (car-safe (car definition)) 'interactive) + (null (cddar definition)) + (cadar definition)))) + (if (and (stringp spec) + (not (string-equal spec "")) + (eq (aref spec 0) ?_)) + (setq definition + (cons (if (string-equal spec "_") + '(interactive) + `(interactive ,(substring spec 1))) + (cdr definition)))) + (if (null reuses) + `(defun ,name ,arglist ,docstring + ,@(cond-emacs-xemacs-macfn definition)) + ;; no dynamic docstring in this case + `(eval-and-compile ; no warnings in Emacs + (defalias ',name + (cond ,@(mapcar (lambda (func) `((fboundp ',func) ',func)) + (nreverse reuses)) + (t ,(if definition + `(lambda ,arglist ,docstring + ,@(cond-emacs-xemacs-macfn definition)) + 'ignore))))))))))) + +(eval-when-compile + (require 'cl) + (defvar init-file-loaded) ; would be useful in Emacs, too... + (defvar file-name-buffer-file-type-alist)) + + + +;;;;########################################################################## +;;;; User Options, Variables +;;;;########################################################################## + + +(defconst template-version "3.1c" + "Current version of package template. +Check for the newest.") + + +;;;=========================================================================== +;;; Customization and initialization +;;;=========================================================================== + +(defgroup template nil + "Use templates, decorate comments, auto-update buffers." + :group 'data + :link '(emacs-commentary-link "template.el") + :link '(url-link "http://emacs-template.sourceforge.net/") + :prefix "template-") + +(defgroup template-comments nil + "Comment decorations in package template." + :group 'template + :prefix "template-") + +(defgroup template-updating nil + "Updating with package template." + :group 'template + :prefix "template-") + +(defgroup template-derivation nil + "Deriving templates for new files." + :group 'template + :prefix "template-") + +(defgroup template-expansion nil + "Expanding the expansion forms in templates." + :group 'template + :prefix "template-") + +(defgroup template-miscellaneous nil + "Miscellaneous configurations of package template." + :group 'template + :prefix "template-") + +;; I could imagine that a future version of package custom could make this +;; `PACKAGE-initialize' stuff easier +(defcustom template-use-package nil + "Pseudo variable. Used to initialize template in custom buffer. +Put `(template-initialize)' into your ~/.emacs to initialize package +template in future sessions. See variable `template-initialize'." + :group 'template + :type '(boolean :format "%{%t%}: %[(template-initialize)%], %v\n" + :on "in use" :off "not yet initialized" + :help-echo "Initialize package Template." + :action template-initialize)) + +(defcustom template-initialize t + "Whether/what to initialize with `template-initialize'. +If t, do full initialization. Otherwise, the value should be a list +with elements. To enable, include + + * `auto' to enable `template-auto-update' and `template-auto-insert', + * `ffap' to make sure that `auto' works with `find-file-at-point', + * `cc-mode' to enable correct C/C++/Java/Antlr comment filling, i.e., + to add `template-c-init-fill-function' to `c-mode-common-hook', + * `de-html-helper' to disable `html-helper's template and time-stamps, + * `keys' to setup the default key bindings, + * `menus' to setup the menus." + :group 'template-miscellaneous + :type '(choice (const :tag "All" t) + (set :value (auto cc-mode keys menus) + (const :tag "Auto Updating/Inserting" auto) + (const :tag "Correct Auto Inserting with Ffap" ffap) + (const :tag "Correct C Comment Filling" cc-mode) + (const :tag "Deactivate html-helper" de-html-helper) + (const :tag "Setup Key Bindings" keys) + (const :tag "Setup Menus" menus)))) + + +;;;=========================================================================== +;;; Menu +;;;=========================================================================== + +(defvar template-comment-menu + '("Comment" + ["Decorate Comment Line" template-single-comment + :active (and (not buffer-read-only) + (memq (template-comment-at-point) + '(none delimited single cont)))] + ["Decorate Comment Block" template-block-comment + :active (and (not buffer-read-only) + (memq (template-comment-at-point) + '(single block)))] + "---" + ["Indent for Comment" indent-for-comment + :active (and comment-start (not buffer-read-only))] + ["Continue Comment" indent-new-comment-line + :active (and comment-start (not buffer-read-only))] + ["Comment Region" comment-region + :active (and comment-start (not buffer-read-only) (mark))] + ["Comment Region 2" (comment-region 2) + :active (and comment-start (not buffer-read-only) (mark))] + ["Comment Region 3" (comment-region 3) + :active (and comment-start (not buffer-read-only) (mark))] + "---" + ["Update Buffer" template-update-buffer + :active (and template-update-buffer-alist (not buffer-read-only))]) + "Menu for comment functions.") + +(defvar template-creation-menu + '("Template Creation" + :filter template-menu-filter + ["Open Template" template-open-template + :active (null (template-buffer-template-p))] + "--" + ["Define User Input" template-define-prompt t] + ["Define Text Register" template-define-register t] + ["Define Message" template-define-message t] + "---" + ["Insert Expansion Form" template-insert-form t]) + "Menu for template creation.") + + +;;;=========================================================================== +;;; Commenting +;;;=========================================================================== + +(defcustom template-max-column -1 + "*Width of the separator line, to use with an empty `comment-end'. +If the value is zero or negative, it is added to `fill-column'. See +also `template-max-column-with-end'." + :group 'template-comments + :type 'integer) + +(defcustom template-max-column-with-end 0 + "*Width of the separator line including a non-empty `comment-end'. +If the value is zero or negative, it is added to `fill-column'. See +also `template-max-column'." + :group 'template-comments + :type 'integer) + +(defcustom template-alt-comment-syntax-alist + '((t "/* " " */")) + "Alternative comment syntax for languages with \"mixed\" comments. +Used by function `template-comment-syntax'. Elements look like + (MODES-OR-REGEXP COMMENT-START COMMENT-END) + +If the current `major-mode' has a empty `comment-end' and a commenting +command does not work at `point' with the usual `comment-start', we +search for the first matching alternative comment syntax in this alist. + +Each element must \"pass\" MODES-OR-REGEXP. If this is a list, it must +include the current major-mode, if this is a regexp, it must match the +`buffer-file-name' without version, otherwise it must be non-nil. + +Then, COMMENT-START and COMMENT-END is used as the alternative comment +syntax if `comment-start-skip' matches COMMENT-START." + :group 'template-comments + :type '(repeat (group (choice (repeat :tag "In major modes" :value nil + function) + (regexp :tag "Buffer matching" :value "") + (sexp :tag "Always" :value t)) + (string :tag "Alt comment start" :value "/* ") + (string :tag "Alt comment end" :value " */")))) + +(defcustom template-comment-indent t + "Non-nil means, indent single-line/block comments. +Commands \\[template-single-comment] and \\[template-block-comment] +indent the comment lines if this value is non-nil and the current major +mode is not a member of `template-indent-mode-disable-list' or if this +value is nil and the current major mode is a member of +`template-indent-mode-enable-list'." + :group 'template-comments + :type 'boolean) + +(defcustom template-indent-mode-disable-list '(sh-mode makefile-mode) + "Major modes not having indented single-line/block comments. +Used if `template-comment-indent' is non-nil. Major modes in which +pressing TAB twice is different from pressing TAB once are good +candidates for this list." + :group 'template-comments + :type '(repeat (function :tag "Major mode"))) + +(defcustom template-indent-mode-enable-list nil + "Major modes having indented single-line/block comments. +Used if `template-comment-indent' is nil." + :group 'template-comments + :type '(repeat (function :tag "Major mode"))) + +(defcustom template-comment-specification-alist + '(("-" "" "" 0) + ("-" "" "" 0) + ("=" "\n\n" "\n" 1) + ("#" "\n\n\f\n" "\n\n" 2)) + "List of specifications for comment functions. +Each specification at LEVEL, starting at 1, is a list + (SEPARATOR BEFORE-BLOCK AFTER-BLOCK DELETE-LINES) + +SEPARATOR is the string which is inserted repeatedly by commands +\\[template-single-comment] and \\[template-block-comment] up to +`template-max-column'. + +After that, \\[template-block-comment] deletes DELETE-LINES after the +comment block and inserts string AFTER-BLOCK at the end of the block and +BEFORE-BLOCK at the front of the block. + +The specification LEVEL to use is determined by: + (1) If the prefix argument is non-nil and its numeric value is > 0, + this value is the LEVEL. + (2) If the prefix argument is nil, and there is an old comment style, + use old comment style. + (3) If `template-comment-specification-special' is a function or the + current major mode has a property with this name and its value is a + function, this function returns the specification. + (4) If `comment-end' is empty and `comment-start' is a string of length + 1: LEVEL is number of repetitions of `comment-start' at the + beginning of the line. Otherwise, if the correctly indented line + starts at the beginning of the line, LEVEL=3, else LEVEL=2." + :group 'template-comments + :type '(repeat (group (string :tag "Separator" :value "-") + (string :tag "Before block" :value "") + (string :tag "After block" :value "") + (integer :tag "Delete lines" :value 0)))) + +(defcustom template-comment-specification-special nil + "Function used for special commenting styles or nil. +See `template-comment-specification-alist' for details." + :group 'template-comments + :type '(choice (const nil) function)) + + +;;;=========================================================================== +;;; Auto updating +;;;=========================================================================== + +(defcustom template-auto-update 'query + "*Whether to update parts of the file when saving the buffer. +When non-nil and `template-auto-update-disable-regexp' does not match +the file name, automatically updates parts of the buffer, see +`template-update-buffer-alist'. With value t or if the entry in the +alist has no prompt, do not ask for confirmation. + +You should have called `template-initialize' to enable this feature." + :group 'template-updating + :type '(radio (const :tag "No" nil) + (const :tag "Without confirmation" t) + (sexp :tag "With confirmation" :format "%t" :value query))) + +(defcustom template-auto-update-disable-regexp nil + "*Regexp matching files not to automatically update. +Value nil matches no file. See `template-auto-update'." + :group 'template-updating + :type '(choice (const :tag "none" nil) regexp)) + +(defcustom template-update-buffer-alist + '((t "Update header in %s? " + (template-update-header t) + (file-name-sans-versions (file-name-nondirectory buffer-file-name))) + ((html-mode) "Update date inside
in %s? " + (-2000 + "\\([0-9]+[ \t]+[A-Za-z][A-Za-z][A-Za-z][ \t]+[0-9]+\\)[ \t\n]*
" + 1) + (format-time-string "%d %b %Y"))) + "Alist used how to update parts of the buffer. +Used by function `template-update-buffer'. Elements look like + (MODES-OR-REGEXP PROMPT TEST NEW REPLACEMENT-FUN) + +Each element must \"pass\" MODES-OR-REGEXP. If this is a list, it must +include the current major-mode, if this is a regexp, it must match the +`buffer-file-name' without version, otherwise it must be non-nil. + +Then, TEST is `eval'd and must return the region = (BEG . END) to be +replaced or nil if nothing should be updated according to the current +element. If TEST is a list and the `car' of TEST is not a function, +`template-update-buffer-region' is used as the default function, i.e., +REPLACEMENT-FUN looks like (LIMIT REGEXP GROUP). Then, check first/last +LIMIT characters in buffer and return region according to GROUP's regexp +group in REGEXP. + +Then, NEW is `eval'd. If it is a string, it is considered as +replacement for the region, otherwise REPLACE-FUN must be non-nil. + +Then, ask user for confirmation with PROMPT where %s is substituted by +the buffer name if PROMPT is a string and `template-auto-update' is not +t. + +Finally, REPLACEMENT-FUN is called the `eval'd NEW and the beginning and +the end of the region returned by TEST. If REPLACEMENT-FUN is nil, just +replace the region by the `eval'd NEW." + :group 'template-updating + :type '(repeat (group (choice (repeat :tag "In major modes" :value nil + function) + (regexp :tag "Buffer matching" :value "") + (sexp :tag "Always" :value t)) + (string :tag "Prompt" :value "Update in %s? ") + (choice (list :tag "Default test" + (choice (const :tag "No limit" nil) + (integer :tag "Limit" -1000)) + regexp + (integer :tag "Regexp group" :value 0)) + (sexp :tag "Eval sexp")) + (sexp :tag "Eval New string") + (option (function :tag "Replacement function"))))) + +(defcustom template-header-lines 3 + "*Last line number which is checked by \\[template-update-header]." + :group 'template-updating + :type 'integer) + +(put 'template-header-lines 'template-secure-value #'integerp) + +(defcustom template-header-regexp-alist + '(("@(#)\\([^ \t\n]+\\)" . 1) + ("^%s[ \t]*\\([^ \t\n%s][^ \t\n]*\\)[ \t]+--" . 1)) + "Alist of regexps matching the file name in the header. +The `car' of each element is the REGEXP with %s, if present, substituted +by the comment start. A second %s, if present, is substitud by a single +letter non-alpha comment start, or the empty string otherwise. + +The `cdr' is the regexp group to be replaced. Used by +\\[template-update-header]. + +The comment start is evaluated from `comment-start', the first character +in the buffer or \"#\". It is assumed that a non-alpha single character +comment start may be repeated. For example, the substituted regexp in +`emacs-lisp-mode' is \"\;+\", in `c++-mode' \"//\"." + :group 'template-updating + :type '(repeat (cons :format "%v" + regexp + (integer :tag "Regexp group" :value 0)))) + + +;;;=========================================================================== +;;; Templates: finding templates +;;;=========================================================================== + +(defcustom template-auto-insert 'query + "*Whether to automatically use template files for new files. +Used if the user gave a non-existent file as argument to a command in +`template-find-file-commands'. When non-nil and a matching template +file can be found, use a template like in `template-new-file'. File +name refinement is never performed, see `template-derivation-alist'. + +With value t, do not ask for confirmation. + +You should have called `template-initialize' to enable this feature." + :group 'template-derivation + :type '(radio (const :tag "No" nil) + (const :tag "Without confirmation" t) + (sexp :tag "With confirmation" :format "%t" :value query))) + +(defcustom template-find-file-commands + '(find-file find-file-other-frame find-file-other-screen + find-file-other-window find-file-at-point ffap nil) + "*Commands which use templates as last resort, see `template-auto-insert'. +See also `template-file-select-commands'. + +Include nil if you want to use templates for non-existing files as +command line arguments when starting Emacs." + :group 'template-derivation + :type '(repeat (function :tag "Command"))) + +(defcustom template-file-select-commands + '(exit-minibuffer minibuffer-complete-and-exit + list-mode-item-mouse-selected + list-mode-item-keyboard-selected) + "*Commands which select the file name via minibuffer/completions. +Checked with commands in `template-find-file-commands'." + :group 'template-derivation + :type '(repeat (function :tag "Command"))) + +(defface template-message-face + '((((class color) (background light)) (:background "pink")) + (t (:bold t))) + "Face for temporary message at point. This only works with XEmacs." + :group 'template-miscellaneous) + +(defcustom template-extension ".tpl" + "*Extension used for template files." + :group 'template-derivation + :type 'string) + +(defcustom template-subdirectories '("./" "Templates/") + "*List of subdirectories for template files. +See `template-derivation-alist' for details." + :group 'template-derivation + :type '(repeat directory)) + +(defcustom template-stop-derivation + (cond ((fboundp 'file-remote-p) 'file-remote-p) + ((fboundp 'efs-ftp-path) 'efs-ftp-path) + ((fboundp 'ange-ftp-ftp-path) 'ange-ftp-ftp-path)) + "If non-nil, function used to determine whether to stop derivation. +If non-nil, function is called with argument DIR. If it returns t, +`template-derivation' stops to search for more project specific +templates, i\.e\., just searches in `template-default-directories'." + :group 'template-derivation + :type '(choice (const :tag "Never" nil) + function)) + +(defcustom template-default-directories + (cons (if (and (not (file-directory-p "~/.templates/")) + (file-directory-p "~/lib/templates")) + (expand-file-name "~/lib/templates/") + (expand-file-name "~/.templates/")) + (and (fboundp 'locate-data-directory) + (let ((dir (locate-data-directory "template"))) + (and dir (list dir))))) + "*List of default directories for template files. +See `template-derivation-alist' for details." + :group 'template-derivation + :type '(repeat directory)) + +(defcustom template-derivation-alist + '(;;(("00readme" "" ".txt" "\\`00") . ("00readme" "" ".txt")) + ((t "" t)) + ((t nil null) . (nil nil t 1)) + (("TEMPLATE" "" t))) + "Alist for template file name derivation and file name refinement. +Template derivation searches for the most specific readable template +file. By default, files with the same RAW part as the name of the new +file are considered to be more specific than files with just the same +EXT part. Also files in the same directory are considered to be more +specific than files in their parent directory or any default template +directory. This behavior can be changed by this alist. + +Each FORM in this alist has the form (TEMPLATE . REFINEMENT). If +TEMPLATE matches, we have found a valid template file and the +corresponding REFINEMENT is used for the file name refinement. + +Before the derivation, the given file name is split into the directory +part DIR, the file name without directory FILE, and the raw part RAW of +FILE, the numbering NUM and the extension EXT. The result is stored in +`template-file'. + +TEMPLATE can have the form (FUNCTION ARG...). If TEMPLATE matches, +FUNCTION, called with arguments ARGs, should return the split template +file name, see `template-split-filename'. + +TEMPLATE can also have the form (T-RAW T-NUM T-EXT F-REGEXP) where all +elements are optional, i.e., have value nil as default. For TEMPLATE to +match, all conditions T-RAW, T-NUM and T-EXT must be met and F-REGEXP, +if non-nil, should match FILE, the non-directory part of the given file +name. If a condition is a string, the corresponding part of the +template file must be equal to it. If t, the part must be equal to +RAW/NUM/EXT of the given file name. If nil, any value will do it. Any +other value acts like t when the part of the given file name is +non-empty, as nil otherwise. + +REFINEMENT can have the form (FUNCTION ARG...). FUNCTION, called with +the list of the split template filename and ARGs as arguments, should +set `template-file' if the file name should be refined. + +REFINEMENT can also have the form (F-RAW F-NUM F-EXT AUTO-NUM) where all +elements are optional, i.e., have value nil as default. If F-RAW, F-NUM +and F-EXT are non-nil, they change RAW/NUM/EXT of `template-file'. A +string will be used as the new part. If t, the corresponding part of +the template name will be used. + +We will use auto numbering in the following two cases: if NUM is +non-empty and the file exists already, or if NUM is empty and AUTO-NUM +is non-nil. Auto numbering looks at the file names in DIR to generate +the next unique number which is at least as high as NUM in the first +case and AUTO-NUM in the second. + +Let us use parts of the default value as examples: + +Use a template with the same RAW part of the given file name and the +same EXT part if provided, e.g., for \"exercise2\" use template +\"exercise.tex.tpl\". Refine file name to use the extension of the +template file, also use auto numbering, e.g., if files \"exercise2.tex\" +and \"exercise3.tex\" exist, refine name to \"exercise4.tex\": + ((t nil null) \. (nil nil t 1)) + +For a file with extension EXT, use TEMPLATE.EXT: + ((\"TEMPLATE\" \"\" t)) + +We could define: If the given file name starts with \"00\", use template +\"00readme.txt.tpl\". Refine file name to \"00readme.txt\": + ((\"00readme\" \"\" \".txt\" \"\\\\`00\") \. (\"00readme\" \"\" \".txt\")) + +Since more than one template file could meet this conditions, the +template derivation searches for first readable file with extension +`template-extension' which is found by the following algorithm: + + forall FORMs in `template-derivation-alist' do + for directory BASE from DIR + while not stopped according to `template-stop-derivation' do + forall subdirectories DIRs in `template-subdirectories' + relative to BASE do + forall TEMPLATEs in DIR do + if check_form (FORM, FULL, TEMPLATE) return TEMPLATE + forall directories DIRs in `template-default-directories' do + forall TEMPLATEs in DIR do + if check_form (FORM, FULL, TEMPLATE) return TEMPLATE + if not used via `template-auto-insert' + forall TEMPLATEs in `template-default-directories' + where name_nondir (TEMPLATE) = \"DEFAULT.tpl\" do + if readable (TEMPLATE) return TEMPLATE + return TEMPLATE in first (`template-default-directories') + where name_nondir (TEMPLATE) = \"DEFAULT.tpl\"" + :group 'template-derivation + :type '(repeat (cons :format "%v" + (sexp :tag "Derivation" :value ("TEMPLATE" nil t)) + (sexp :tag "Refinement" :value nil)))) + + +;;;=========================================================================== +;;; Templates: expanding templates +;;;=========================================================================== + +(defcustom template-confirm-insecure t + "*Non-nil means, ask whether to use insecure template expansions. +Only set this to nil if you ALWAYS check template files before using +it!" + :group 'template-expansion + :type 'boolean) + +(put 'template-confirm-insecure 'risky-local-variable t) + +(defcustom template-message-buffer "*Template Message*" + "If non-nil, name of buffer where messages are shown. +The following messages will be displayed in definition sequence before +the expansion has taken place: + - :before messages, see `template-definition-start', + - user defined prompts if `template-message-prompt-format' is non-nil, + - user defined registers when there has been a :before message before, + see `template-message-register-format'. + +The following messages will be displayed in definition sequence after +the expansion has taken place: + - :after messages, see `template-definition-start', + - user defined registers, display them at point if the value of this + variable is nil, see `template-message-register-format'." + :group 'template-miscellaneous + :type '(choice (const :tag "None" nil) + (string :tag "Buffer Name"))) + +(defcustom template-message-prompt-intro + "Template expansion will ask for input with the following prompts:" + "Default intro message used before listing user defined prompts. +Used with :before messages, see `template-message-prompt-format'." + :group 'template-miscellaneous + :type '(choice (const :tag "None" nil) + (string :tag "Intro text"))) + +(defcustom template-message-prompt-format " %s" + "If non-nil, format string for user defined prompts. +If non-nil and `template-message-buffer' is non-nil, user defined +prompts will be listed before starting the expansions. Prompts can be +defined as specified in the docstring of `template-definition-start'. +For each PROMPT, this format string will be used with substitution +PROMPT/%s. + +If no :before message has been defined before, use, if non-nil, +`template-message-prompt-intro' as the first :before message." + :group 'template-miscellaneous + :type '(choice (const :tag "No prompt" nil) + (string :tag "Format string"))) + +(defcustom template-message-register-intro + "Template has defined the following registers:" + "Default intro message used before listing user defined prompts. +Used with :after messages, see `template-message-register-format'." + :group 'template-miscellaneous + :type '(choice (const :tag "None" nil) + (string :tag "Intro text"))) + +(defcustom template-message-register-format " %c:\t\"%s\"\t%s" + "If non-nil, format string for user defined registers. +If non-nil, user defined text registers will be listed. Registers can +be defined as specified in the docstring of `template-definition-start'. +For each register CHAR with contents CONTENTS and optional comment +COMMENT, this format string will be used with substitution CHAR/%c, +CONTENT/%s and \(COMMENT/%s or \"\"/%s). + +The list of register definitions will be displayed: + - at point if `template-message-buffer' is nil, + - with :before messages if there has been at least one :before message + defined before and if `template-message-buffer' is non-nil, + - with :after messages if `template-message-buffer' is non-nil. + If no :after message has been defined before, use, if non-nil, + `template-message-register-intro' as the first :after message." + :group 'template-miscellaneous + :type '(choice (const :tag "No register content" nil) + (string :tag "Format string"))) + +(defcustom template-message-timeout 600 + "*Maximum duration the temporary message will be displayed at point. +Any user event will also make the temporary message disappear. The +temporary message uses face in `template-message-face'." + :group 'template-miscellaneous + :type 'integer) + +(put 'template-message-timeout 'template-secure-value #'integerp) + +(defcustom template-date-format "%d %b %Y" + "*Date/time format used with the expansion form (>>>DATE<<<). +See `template-default-expansion-alist' and `format-time-string'. See +also `template-time-format'." + :group 'template-expansion + :type 'string) + +(put 'template-date-format 'template-secure-value #'stringp) + +(defcustom template-time-format "%T" + "*Date/time format used with the expansion form (>>>TIME<<<). +See `template-default-expansion-alist' and `format-time-string'. See +also `template-date-format'." + :group 'template-expansion + :type 'string) + +(put 'template-time-format 'template-secure-value #'stringp) + +(defcustom template-string-default "%0.0S" + "*Format string used for non-string variable extensions. +If SYMBOL in (\"KEY\" \. SYMBOL) is not a string, use string with +substitution SYMBOL/%S. Default value \"%0.0S\" causes to print +nothing. See `template-definition-start'." + :group 'template-expansion + :type 'string) + +(put 'template-string-default 'template-secure-value #'stringp) + +(defcustom template-expansion-format "(>>>%s<<<)" + "Format string for expansion forms. +Is a expansion form with substitution KEY/%s. The value should +correspond with `template-expansion-regexp'. Used by +`template-insert-form'." + :group 'template-expansion + :type 'string) + +(put 'template-expansion-format 'template-secure-value #'stringp) + +(defcustom template-expansion-regexp "(>>>\\([-A-Za-z0-9_]+\\)<<<)" + "Regexp matching strings which are replaced by their expansions. +The first regexp group contains the KEY used by the per-template +expansion, see `template-definition-start' and the global expansions in +`template-expansion-alist' and `template-default-expansion-alist'. The +value should correspond with `template-expansion-alist'. + +If there is no defined expansion for the key, ask the user for a +replacement, see `template-read'. If the key is matched by +`template-register-regexp', store buffer position in register, see +`template-register', . + +If you want to use a text literally which is matched by this regexp, use +the zero expansion form (>>>ZERO_FORM<<<)." + :group 'template-expansion + :type 'regexp) + +(put 'template-expansion-regexp 'template-secure-value #'stringp) + +(defcustom template-literal-environment '("LITERAL" . "/LITERAL") + "Environment for literal text in template. +Looks like (OPEN . CLOSE). Text between expansion forms with keys OPEN +and CLOSE is not expanded. If you change OPEN, you should change key +\"LITERAL\" in `template-default-expansion-alist' accordingly." + :group 'template-expansion + :type '(cons (string :tag "Open tag") (string :tag "Close tag"))) + +(defcustom template-register-regexp "\\`[0-9]\\'" + "*Regexp matching keys for storing point positions in registers. +These keys use `template-register' as the default expansion instead of +`template-read'. See `template-expansion-regexp'. If a register is used +twice, it is marked by a \"*\" in the echo area after the expansion." + :group 'template-expansion + :type 'regexp) + +(put 'template-register-regexp 'template-secure-value #'stringp) + +(defcustom template-expansion-alist nil + "User defined expansions forms. +Predefined expansion forms for `template-expansion-regexp'. Each entry +has the form (KEY . SEXP). These expansion forms shadow those in +`template-default-expansion-alist' and are shadowed by those in the +per-template definition section. See `template-definition-start'." + :group 'template-expansion + :type '(repeat (cons :format "%v" + (string :tag "Key" :value "") + (repeat :tag "Evaluate all" sexp)))) + +(put 'template-expansion-alist 'risky-local-variable t) + +(defvar template-default-expansion-alist + '(("POINT" (setq template-point (point-marker))) ; point + ("MARK" (setq template-mark (point-marker))) ; mark + ("DIR" (insert (car template-file))) ; directory + ("FILE" (insert (cadr template-file))) ; file name without directory + ("FILE_SANS" (insert (nth 2 template-file) + (nth 3 template-file))) + ("FILE_RAW" (insert (nth 2 template-file))) ; raw file name without number + ("FILE_NUM" (insert (nth 3 template-file))) ; number + ("FILE_UPCASE" (insert (upcase (nth 2 template-file)) + (nth 3 template-file))) + ("FILE_EXT" (or (string= (nth 4 template-file) "") ; extension + (insert (substring (nth 4 template-file) 1)))) + ("DATE" (template-insert-time template-date-format)) + ("TIME" (template-insert-time template-time-format)) + ("VC_DATE" (set-time-zone-rule "UTC") + (template-insert-time "%Y/%m/%d %T" "0000/00/00 00:00:00") + ;; using saved `current-time-zone' doesn't work, but nil does + (set-time-zone-rule nil)) + ("YEAR" (template-insert-time "%Y" "0000")) + ("ISO_DATE" (template-insert-time "%Y-%m-%d" "0000-00-00")) + ("COMMENT" (template-read "Initial comment: ")) ; comment + ("AUTHOR" (insert (or user-mail-address ; author + (and (fboundp 'user-mail-address) + (user-mail-address)) + (concat (user-login-name) "@" (system-name))))) + ("USER_NAME" (insert (or (and (boundp 'user-full-name) ; user name + user-full-name) + (user-full-name)))) + ("LOGIN_NAME" (insert (user-login-name))) ; login name + ("HOST_ADDR" (insert (or (and (boundp 'mail-host-address) ; host address + (stringp mail-host-address) + mail-host-address) + (system-name)))) + ("LITERAL" (if (search-forward (format template-expansion-format + (cdr template-literal-environment)) + nil 'limit) + (delete-region (match-beginning 0) (match-end 0)))) + ("ZERO_FORM")) ; zero form + "Predefined default expansions forms. +Predefined expansion forms for `template-expansion-regexp'. Each entry +has the form (KEY . SEXP). These expansion forms are shadowed by those +in `template-expansion-alist' and by those in the per-template +definition section. See `template-definition-start'. + +The default predefined expansion forms are --default is inserting--: + (>>>POINT<<<) set point + (>>>MARK<<<) set mark, jump to it with \\[exchange-point-and-mark] + (>>>DIR<<<) directory: /home/clstaff/wedler/lib/ + (>>>FILE<<<) file w/o directory: text1.txt + (>>>FILE_SANS<<<) file name w/o extension: text1 + (>>>FILE_RAW<<<) raw file name: text + (>>>FILE_NUM<<<) number in name: 1 + (>>>FILE_EXT<<<) extension: txt + (>>>FILE_UPCASE<<<) upcase file name w/o extension: TEXT1 + (>>>DATE<<<) date using `template-date-format': 11 Jan 1999 + (>>>TIME<<<) time using `template-time-format': 11:58:49 + (>>>YEAR<<<) the year: 1999 + (>>>ISO_DATE<<<) ISO 8601 date: 1999-01-11 + (>>>VC_DATE<<<) UTC date/time for vc: 1999/01/11 10:58:49 + (>>>COMMENT<<<) ask user for initial comment + (>>>AUTHOR<<<) author, i.e., `user-mail-address' + (>>>USER_NAME<<<) user name: Christoph Wedler + (>>>LOGIN_NAME<<<) login name: wedler + (>>>HOST_ADDR<<<) Host address: fmi.uni-passau.de + (>>>LITERAL<<<) literal text up to (>>>/LITERAL<<<) + (>>>ZERO_FORM<<<) zero form, i.e., insert nothing. Useful to insert + a text part matched by `template-expansion-regexp' literally. + +There are aliases with one-letter keys, see `template-key-alias-alist'. + +It is useful to follow the following conventions: upper case keys for +predefined extensions, lower case and digits for per-template and the +following default expansions: + (>>>0<<<) to (>>>9<<<) set registers 0 to 9, jump to it with + \\[jump-to-register] 0 etc., see `template-register-regexp' + (>>>x<<<) where x is any unused letter sequence: ask user.") + +(put 'template-default-expansion-alist 'risky-local-variable t) + +(defvar template-key-alias-alist + '(("P" . "POINT") + ("M" . "MARK") + ("D" . "DIR") + ("F" . "FILE") + ("R" . "FILE_RAW") + ("N" . "FILE_NUM") + ("B" . "FILE_UPCASE") + ("E" . "FILE_EXT") + ("T" . "DATE") + ("V" . "VC_DATE") + ("Y" . "YEAR") + ("I" . "ISO_DATE") + ("C" . "COMMENT") + ("A" . "AUTHOR") + ("U" . "USER_NAME") + ("L" . "LOGIN_NAME") + ("H" . "HOST_ADDR") + ("Z" . "ZERO_FORM")) + "Alist to support the old one-letter predefined expansion forms. +Used for `template-expansion-alist' and +`template-default-expansion-alist'.") + +(defcustom template-definition-start + ">>>TEMPLATE-DEFINITION-SECTION<<<" + "Header for the per-template definition section. +The region following the the first match of this regexp defines the +per-template definition section. The region will be deleted before the +actual expansion, see `template-new-file'. If you use the \"Local +Variables:\" section, define it before this region. + +The definition section defines expansion forms for strings KEYs matched +by `template-expansion-regexp' which might shadow those in +`template-expansion-alist' and `template-default-expansion-alist': + + (\"KEY\"): zero form, same as (>>>ZERO_FORM<<<) in default value of +`template-default-expansion-alist', useful for inserting text matched by +`template-expansion-regexp' literally. + + (\"KEY\". CHAR): CHAR is the register where the current buffer +position is stored, see `template-register-regexp'. + + (\"KEY\" \"PROMPT\" \"PREFIX\" \"SUFFIX\" \"DEFAULT\" AGAIN-P) where +the last four arguments are optional: ask user with PROMPT for a STRING. +If STRING is not \"\", insert PREFIX STRING SUFFIX, otherwise DEFAULT. +For AGAIN-P, see `template-read'. To define, use +\\[template-define-prompt]. + + (\"KEY\" \"PROMPT\" (\"ANSWER\" \. \"TEXT\")...): ask user with PROMPT +for an input with completion over all ANSWERs and insert corresponding +TEXT. Expansion forms in TEXT will be expanded. + + (\"KEY\" \"PROMPT\" (t \. \"TEXT-y\") (nil \. \"TEXT-n\")): ask user +with PROMPT a \"y or n\" question with `y-or-n-p' and insert TEXT-y or +TEXT-n, correspondingly. Expansion forms in TEXT-X will be expanded. +The y-case and the n-case are optional and can be exchanged. + + (\"KEY\" \. SYMBOL): insert value of SYMBOL; if value is no string at +the time of the replacement, use `template-string-default' as format +string for SYMBOL. + + (\"KEY\" COMMAND \. PREFIX): COMMAND is a symbol or a vector and is +called with `command-execute' after setting `prefix-arg' to PREFIX, not +evaluated. If COMMANDs symbol property `template-secure-command' is +nil, the form is insecure. If that symbol property is a function, it is +called with PREFIX to check whether COMMAND could be called directly +with PREFIX as remaining arguments. + + (\"KEY\" SEXPR...): evaluate SEXPR during the expansion, see +`template-expansion-alist' for examples. This form is insecure. + +There are other per-template definitions: + + \"MESSAGE\": additional line displayed at point until first user event +or after `template-message-timeout' seconds. The lines are displayed +with face in `template-message-face'. With active form selector +:before, define a message which is displayed in +`template-message-buffer' before the exansion has started. With active +form selector :after, define a message which is displayed in +`template-message-buffer' after the exansion has taken place. To +define interactively, use \\[template-define-message]. + + (CHAR \. \"CONTENTS\"): Set register CHAR to have contents CONTENTS. +CONTENTS can then be inserted into a buffer with \\[insert-register] CHAR. + + (CHAR \"CONTENTS\" COMMENT) where COMMENT is optional: Set register +CHAR to have contents CONTENTS. CONTENTS can then be inserted into a +buffer with \\[insert-register] CHAR. Also display an additional line +at point to show the contents with COMMENT. To define, use +\\[template-define-register]. + +The following forms depend on the active form selector which is the last +of the following expansion forms: + - :before: \"MESSAGE\" will be displayed before the expansion + - :after: \"MESSAGE\" will be displayed after the expansion + - :eval-before: execute COMMAND and SEXPR before expansion + - :eval-after: execute COMMAND and SEXPR after expansion + - nil, deprecated: with the first form, the active form selector is + :eval-before, with the second, it is :eval-after. + + (VARIABLE . VALUE): set SYMBOL's local value to VALUE, not evaluated. +This form is only secure if VARIABLE has a symbol property +`template-secure-value' which returns non-nil when applied to VALUE, not +evaluated. This form is useful for variables which determine the +expansion, like `template-time-format' and `template-date-format'. For +local variables in your new file, use the normal way via the \"Local +Variables:\" section. The active form selector must not be :eval-before +or :eval-after. + + COMMAND: COMMAND is a symbol or a vector and is called with +`command-execute' before the expansion with form selector :eval-before, +and after the expansion with form selector :eval-after. If COMMANDs +symbol property `template-secure-command' is nil, the form is insecure. +You should use the safe command `normal-mode' in the pre-expansion forms +if the expansion forms depend on the correct major mode. + + SEXPR: evaluate SEXPR before the expansion with form selector +:eval-before, and after the expansion with form selector :eval-after. +This form is insecure. + +If any insecure forms have been used, the user of the template will be +asked whether to use the template, see `template-confirm-insecure'." + :group 'template-expansion + :type 'string) + + + +;;;;########################################################################## +;;;; Commenting +;;;;########################################################################## + + +(defunx template-point-at-bol (&optional count) + :emacs-only line-beginning-position + :xemacs-only point-at-bol) + +(defunx template-point-at-eol (&optional count) + :emacs-only line-end-position + :xemacs-only point-at-eol) + +(defunx template-char-or-char-int-p (object) + :emacs-only integerp + :xemacs-only char-or-char-int-p) + +(defunx template-char-or-int-to-char (object) + :emacs-only identity + "Convert character or integer OBJECT into the equivalent character." + (if (characterp object) object (int-to-char object))) + + +;;;=========================================================================== +;;; Main functions +;;;=========================================================================== + +;;;###autoload +(defun template-single-comment (&optional arg) + "Decorate the comment in the current line with dashes and alike. +The line must be a comment-only line or must contain a comment ending by +eol. That is, jump to the end of the current line and insert the dashes +and the final comment end-string up-to the fill position. Prefix +argument ARG and `template-comment-specification' determines the comment +style to use. The length of the resulting line is determined by +`template-max-column' and `template-max-column-with-end'." + (interactive "*P") + (let* ((orig (point-marker)) + (syntax0 (and comment-start comment-start-skip + (condition-case nil + (template-comment-syntax orig 'boc) + (error nil)))) + (syntax (cond ((cdr syntax0) + (template-comment-syntax orig)) + (syntax0 + (condition-case nil + (template-comment-syntax (point-marker)) + (error syntax0))) + (t + (back-to-indentation) + nil))) + (sep (template-comment-separator-regexp syntax)) + (end (template-point-at-eol)) + old) + (save-excursion + (cond ((re-search-forward sep end t) + ;; with sep in current line + (setq old (buffer-substring (match-beginning 1) (match-end 1))) + (delete-region (match-beginning 0) (match-end 0))) + ((cdr syntax) ; with start-end comment + (if (looking-at (concat "[ \t]*\\(.+\\)?" + (regexp-quote (cadr syntax)) + "[ \t]*\\(.+\\)?$")) + (if (or (match-beginning 1) (match-beginning 2)) + (error "This line contains non-separator chars and %S" + (cadr syntax)) + ;; Delete comment-end. Don't delete its first char if it is + ;; the same as the second of comment-start. + (delete-region (if (and (= (length (car syntax)) 2) + (= (length (cadr syntax)) 2) + (eq (aref (car syntax) 1) + (aref (cadr syntax) 0))) + (1+ (match-beginning 0)) + (match-beginning 0)) + (match-end 0)))) + (goto-char (cddr syntax)) + (if (re-search-forward sep end t) + ;; sep in line between comment-start and point-at-eol + (setq old (buffer-substring (match-beginning 1) + (match-end 1))))))) + (template-insert-separator + (car (template-comment-specification arg old syntax)) + nil syntax))) +(put 'template-single-comment 'template-secure-command t) + +;;;###autoload +(defun template-block-comment (&optional arg) + "Decorate the current block of comment-only lines with dashes and alike. +That is, surround the the contiguous comment-only lines around point +with extra lines containing dashes and alike and to put the correct +number of newlines around the block. + +Barf if the comment syntax at point has a non-empty `comment-end' or if +point is not in a comment-only line. + +A block comment consists of all neighboring lines which start with +spaces and `comment-start'. If `comment-start' is a string of length 1, +the number of repetitions of `comment-start' must be the same or larger +than in the line where the command is invoked from, too. + +Prefix argument ARG and `template-comment-specification' determines the +comment style to use. The length of the separator line is determined by +`template-max-column'. + +This command can also be used with point in an empty line after a block +comment. A second invocation of this command directly after a +successful invocation deletes the remaining empty lines from the current +line on." + (interactive "*P") + (let* ((orig (point-marker)) + (syntax (progn + (end-of-line) + (skip-chars-backward " \t\n\f") + (template-comment-syntax orig)))) + (when (cdr syntax) + (goto-char orig) + (error "Command only works with comments terminated by end-of-line")) + + (if (and (eq last-command 'template-block-comment-success) + (looking-at "[ \t]*$")) + (template-insert-newline "" nil (1- (template-point-at-bol))) + (let* ((prefix (concat "[ \t]*" (regexp-quote (car syntax)))) + (sepline (concat prefix "[ \t]*" + (template-comment-separator-regexp syntax))) + old block-beg block-end def) + ;; go to the first line with same comment prefix --------------------- + (beginning-of-line) + (while (and (not (bobp)) (looking-at prefix)) + (beginning-of-line 0)) + (or (looking-at prefix) (beginning-of-line 2)) + (while (looking-at sepline) + (setq old (buffer-substring (1- (match-end 0)) (match-end 0))) + (kill-line 1)) + (setq block-beg (point-marker)) + ;; go to the last line with same comment prefix ---------------------- + (while (looking-at prefix) + (template-indent-according-to-mode) + (beginning-of-line 2)) + (if (eobp) (newline)) + (setq block-end (copy-marker (point) t)) + (while (progn (forward-line -1) (looking-at sepline)) + (setq old (buffer-substring (1- (match-end 0)) (match-end 0))) + (kill-line 1)) + ;; insert separator lines -------------------------------------------- + (goto-char block-beg) + (set-marker block-beg nil) + (back-to-indentation) + (setq def (template-comment-specification arg old syntax)) + (beginning-of-line) + (template-insert-newline (cadr def)) + (template-insert-separator (car def) (car syntax) syntax) + (goto-char block-end) + (set-marker block-end nil) + (template-insert-separator (car def) (car syntax) syntax) + (template-insert-newline (caddr def) + (and (cadddr def) + (save-excursion + (forward-line (cadddr def)) + (point)))) + (setq this-command 'template-block-comment-success))) + (template-indent-according-to-mode) + (back-to-indentation))) +(put 'template-block-comment 'template-secure-command t) + + +;;;=========================================================================== +;;; Check comment start, return specification +;;;=========================================================================== + +(defun template-indent-according-to-mode () + "Indent line according to `template-comment-indent'." + (if (if template-comment-indent + (not (memq major-mode template-indent-mode-disable-list)) + (memq major-mode template-indent-mode-enable-list)) + (indent-according-to-mode))) + +(defun template-default-comment () + "Return default comment according to current position." + (if comment-start + (substring comment-start 0 (string-match "[ \t]\\'" comment-start)) + (if (eolp) "#" + (let ((default (buffer-substring (point) (1+ (point))))) + (if (string-match "[A-Za-z]" default) "#" default))))) + +(defun template-comment-at-point () + "Return the comment syntax at the current position. +Return nil, if no commenting command can be used, i.e., if point is not +in a comment-only line. Return `none' if the `major-mode' doesn't +define a comment syntax. Return `delimited' if point is between +`comment-start' and a non-empty `comment-end'. Return `single' if point +is in a comment line where the comment syntax has a empty `comment-end', +return `block' if point is in an empty line after such a comment line." + (if (and comment-start comment-start-skip) + (save-excursion + (let ((orig (point))) + (condition-case nil + (progn + (end-of-line) + (skip-chars-backward " \t\n\f") + (if (cdr (template-comment-syntax orig t)) 'delimited + (if (< (template-point-at-eol) orig) 'block 'single))) + (error + (condition-case nil + (progn + (goto-char orig) + (beginning-of-line) + (when (re-search-forward comment-start-skip + (template-point-at-eol) t) + (goto-char (or (match-end 1) (match-beginning 0))) + (unless (or (cdr (template-comment-syntax orig 'boc)) + (< (template-point-at-eol) orig)) + 'cont))) + (error nil)))))) + 'none)) + +(defun template-comment-syntax (orig &optional no-indent) + "Return the comment syntax at ORIG. Signal error if not in comment. +Return (COMMENT-START) if the comment syntax has an empty `comment-end'. +Return (COMMENT-START COMMENT-END . START-POS) if the comment syntax has +a non-empty `comment-end' where START-POS is the position of the first +character inside the comment. Move point to first character after the +comment start or the first non-whitespace character on this line. + +ORIG should be the same as `point' or in a empty line after `point'. + +If optional argument NO-INDENT is nil, indents the current line +according to `template-comment-indent' and `indent-according-to-mode'. +If NO-INDENT is `boc', move point to the beginning of the comment. + +COMMENT-START is stripped off its final spaces, COMMENT-END off its +initial spaces." + (unless (and comment-start comment-start-skip) + (error "No comment syntax has been defined for %s" major-mode)) + (if (eq no-indent 'boc) + (progn + (beginning-of-line) + (if (re-search-forward comment-start-skip (template-point-at-eol) t) + (goto-char (or (match-end 1) (match-beginning 0))))) + (or no-indent (template-indent-according-to-mode)) + (back-to-indentation)) + (let* ((string (template-default-comment))) + (if (string= comment-end "") + (if (looking-at (concat (regexp-quote string) + (and (= (length string) 1) + (not (eq no-indent 'boc)) + "+"))) + (progn + (goto-char (match-end 0)) + (list (buffer-substring (match-beginning 0) (point)))) + (let ((alist template-alt-comment-syntax-alist) + elem c-start c-end) + (while alist + (setq elem (pop alist)) + (and (template-match-modes-or-regexp (car elem)) + (string-match comment-start-skip (cadr elem)) + (setq c-start (cadr elem) + c-end (caddr elem) + alist nil))) + (template-comment-syntax-0 orig c-start c-end string))) + (template-comment-syntax-0 orig comment-start comment-end)))) + +(defun template-comment-syntax-0 (orig c-start c-end &optional single) + ;; checkdoc-params: (orig c-start c-end single) + "Internal function for `template-comment-syntax'." + (unless (and (stringp c-start) (stringp c-end) (not (string= c-end ""))) + (goto-char orig) + (error "Line does not start with %S" + (or single (template-default-comment)))) + (setq c-start (substring c-start 0 (string-match "[ \t]\\'" c-start)) + c-end (if (string-match "\\`[ \t]+" c-end) + (substring c-end (match-end 0)) + c-end)) + (cond ((looking-at (regexp-quote c-start)) + (goto-char (match-end 0)) + (cons c-start (cons c-end (point)))) + ((save-excursion + (when (re-search-backward (concat "^[ \t]*" (regexp-quote c-start)) + nil t) + (goto-char (match-end 0)) + (let ((match (point))) + (unless (when (search-forward c-end orig t) + (skip-chars-forward " \t") + (< (point) orig)) + (cons c-start (cons c-end match))))))) + (t + (goto-char orig) + (if single + (error "Not inside a comment (%S or %S-%S) starting in new line" + single c-start c-end) + (error "Not inside a comment (%S-%S) starting in new line" + c-start c-end))))) + + +;;;=========================================================================== +;;; Comment specification +;;;=========================================================================== + +;; A simple `mapconcat' is likely to slow down Emacs' regexp search algorithm +;; considerably (backtracking => near-infloop). +(defun template-comment-separator-regexp (syntax) + "Return regexp matching separator comment lines. +The regexp also matches if the lines ends with parts of COMMENT-END in +argument SYNTAX, see `template-comment-syntax'." + (let ((estring (cadr syntax)) + (alist template-comment-specification-alist) + (chars nil) + str i c) + (while alist + (setq str (car (pop alist))) + (when str + (setq i (length str)) + (while (>= (decf i) 0) + ;; (pushnew (aref str i) chars), but requires cl at runtime: + (or (memq (setq c (aref str i)) chars) (push c chars))))) + (concat "\\(" + (mapconcat (lambda (c) (regexp-quote (char-to-string c))) + (or chars "#") + "\\|") + (if estring + (concat "\\)+[ \t]*" + (mapconcat (lambda (c) + (regexp-quote (char-to-string c))) + estring + "?") + "?[ \t]*$") + "\\)+[ \t]*$")))) + +(defun template-comment-specification (arg old syntax) + "Return the comment specification to use. +See `template-comment-specification-alist' for details. ARG is the +prefix argument, OLD the SEPARATOR of the old comment style and SYNTAX +is the comment syntax returned by `template-comment-syntax'." + (and arg (setq arg (prefix-numeric-value arg))) + ;; assumes point-at-indentation + (or (and arg (> arg 0) + (if (< (length template-comment-specification-alist) arg) + (car (last template-comment-specification-alist)) + (nth (1- arg) template-comment-specification-alist))) + (and (null arg) old + (assoc old template-comment-specification-alist)) + (and (functionp template-comment-specification-special) + (funcall template-comment-specification-special)) + (and (functionp (get major-mode 'template-comment-specification-special)) + (funcall (get major-mode 'template-comment-specification-special))) + (and syntax + (template-comment-specification + (if (or (cdr syntax) (> (length comment-start) 1)) + (save-excursion + (if (cddr syntax) (goto-char (cddr syntax))) + (beginning-of-line) + (if (looking-at "[ \t]") 2 3)) + (length (car syntax))) + nil nil)) + '("-" "" "" 0))) + + +;;;=========================================================================== +;;; Inserting +;;;=========================================================================== + +(defun template-insert-newline (string &optional limit start-limit) + "Deletes blank lines around point and insert STRING. +After optional LIMIT and before optional START-LIMIT, no character will +be deleted." + (let ((start (save-excursion + (skip-chars-backward " \t\n\f" start-limit) + (or (bobp) (forward-line 1)) + (point))) + (end (save-excursion + (skip-chars-forward " \t\n\f" limit) + (beginning-of-line) + (point)))) + (if (> end start) (delete-region start end))) + (or (bobp) (insert string))) + +(defun template-insert-separator (separator &optional cstring syntax) + "Insert separator line at point. +If CSTRING is not nil, insert in special line which starts with CSTRING. +Insert SEPARATOR repeatedly. End the line with COMMENT-END as specified +in `template-comment-syntax'." + (when separator + (when cstring + (open-line 1) + (insert cstring) + (template-indent-according-to-mode)) + (end-of-line) + (let* ((estring (cadr syntax)) + (max-column (if estring + template-max-column-with-end + template-max-column)) + (max (- (if (> max-column 0) max-column (+ fill-column max-column)) + (length separator) + (length estring)))) + (while (<= (current-column) max) (insert separator)) + (if (>= (length separator) (- (current-column) max)) + (insert (substring separator 0 (- max (current-column))))) + (if estring (insert estring)) + (if cstring (forward-line 1))))) + + +;;;=========================================================================== +;;; Adaptations: cc-mode +;;;=========================================================================== + +;; There isn't really anything I can do against the filling of "/**" in C, C++ +;; and Antlr mode (it is correct in Java), it should be done in the cc-mode +;; package. Similar for filling "*/" with the previous line... + +(defun template-c-fill-paragraph (&optional arg) + ;; checkdoc-params: (arg) + "Like \\[c-fill-paragraph] but handles comment separator lines." + (let* ((regexp (concat "\\|[ \t]*\\(/[*/]\\|\\*\\)[ \t]*" + (template-comment-separator-regexp '("/*" "*/")))) + (paragraph-start (concat paragraph-start regexp)) ;#dynamic + (paragraph-separate (concat paragraph-separate regexp))) + (c-fill-paragraph arg))) + +(defun template-c-init-fill-function () + "Set `fill-paragraph-function' to use `template-c-fill-paragraph'." + (when (boundp 'fill-paragraph-function) + (make-local-variable 'fill-paragraph-function) + (setq fill-paragraph-function 'template-c-fill-paragraph))) + + + +;;;;########################################################################## +;;;; Updating (File Name in Header) +;;;;########################################################################## + + +;;;=========================================================================== +;;; General updating +;;;=========================================================================== + +(defun template-update-buffer-region (limit regexp group) + "Return region = (BEG . END) in buffer to be updated. +If LIMIT is positive, check first LIMIT characters in buffer, otherwise +check last -LIMIT characters in buffer for a text to be matched by +REGEXP. Return region according to GROUP's regexp group in REGEXP." + (let ((case-fold-search nil)) + (goto-char (if limit + (if (natnump limit) (point-min) (+ (point-max) limit)) + (point-min))) + (when (re-search-forward regexp + (if (natnump limit) + (+ (point-min) limit) + (point-max)) + t) + (cons (match-beginning group) (match-end group))))) + +(defun template-match-modes-or-regexp (modes-or-regexp) + "Return non-nil, if the current buffer passes MODES-OR-REGEXP. +If MODES-OR-REGEXP is a list, it must include the current `major-mode', +if it is a regexp, it must match the `buffer-file-name' without version, +otherwise it must be non-nil." + (if (stringp modes-or-regexp) + (and buffer-file-name + (string-match modes-or-regexp + (file-name-sans-versions buffer-file-name))) + (or (nlistp modes-or-regexp) (memq major-mode modes-or-regexp)))) + +(defun template-update-buffer (&optional arg) + "Update buffer according to `template-update-buffer-alist'. +Do not do anything if `template-auto-update-disable-regexp' matches the +file name or if `template-auto-update' is nil. When optional ARG is +non-nil, i.e., if called interactively *without* prefix arg, always +update." + (interactive (list (null current-prefix-arg))) + (when (or arg + (and template-auto-update buffer-file-name + (null (and template-auto-update-disable-regexp + (string-match template-auto-update-disable-regexp + buffer-file-name))))) + (save-excursion + (save-restriction + (widen) + (let ((alist template-update-buffer-alist) + (case-fold-search (memq system-type '(vax-vms ms-dos windows-nt))) + stamp prompt region new) + (while alist + (setq stamp (pop alist)) + (condition-case nil + (and (template-match-modes-or-regexp (pop stamp)) + ;; Run TEST --------------------------------------------- + (setq prompt (pop stamp) + region (pop stamp) ; TEST + region (eval (if (or (atom region) + (functionp (car region))) + region + (cons 'template-update-buffer-region + region)))) + (if (stringp (setq new (eval (pop stamp)))) + (null (string= (buffer-substring (car region) + (cdr region)) + new)) + (car stamp)) + ;; user confirmation, replacement ----------------------- + (or (null prompt) + arg + (eq template-auto-update t) + (y-or-n-p (format prompt (buffer-name)))) + (progn + (goto-char (car region)) + (if (car stamp) + (funcall (car stamp) new (car region) (cdr region)) + (delete-region (car region) (cdr region)) + (insert new)))) + (error nil)))))))) + + +;;;=========================================================================== +;;; Update header +;;;=========================================================================== + +;;;###autoload +(defun template-update-header (&optional show) + "Replace old file name in header with current file name. +If SHOW is t, just return region of the filename or nil. Otherwise, +replace filename if possible and signal an error if SHOW is nil and +there is no filename in the header. See `template-header-lines' and +`template-header-regexp-alist'." + (interactive "*P") + (if buffer-file-name + (save-excursion + (goto-char (point-min)) + (let ((case-fold-search nil) + (comment-regexp (template-default-comment)) ; at `point-min'! + (end (progn (forward-line template-header-lines) (point))) + (alist template-header-regexp-alist) + (disallowed "") + group) + (if (string-match "[A-Za-z]\\|.." comment-regexp) + (setq comment-regexp (regexp-quote comment-regexp) + disallowed "") + (or (eq comment-regexp '(?\])) + (setq disallowed comment-regexp)) + (setq comment-regexp (concat (regexp-quote comment-regexp) "+"))) + (while alist + (goto-char (point-min)) + (if (re-search-forward (format (caar alist) + comment-regexp disallowed) + end t) + (setq group (cdar alist) + alist nil) + (setq alist (cdr alist)))) + (if (and group (match-beginning group)) + (if (eq show t) + (cons (match-beginning group) (match-end group)) + (goto-char (match-beginning group)) + (delete-region (point) (match-end group)) + (insert (file-name-sans-versions + (file-name-nondirectory buffer-file-name))) + t) + (if show nil (error "No file name in header"))))) + (if show nil (error "Buffer is not visiting a file")))) + + + +;;;;########################################################################## +;;;; Templates +;;;;########################################################################## + + +(defvar template-history nil + "History, used by `template-read'.") + +(defvar template-choice-history nil + "History, used by `template-choice'.") + +(put 'normal-mode 'template-secure-command t) + +(defvar template-all-templates nil + "Internal variable. Template files used for template derivation.") +(defvar template-file nil + "Partitioned name of new file: (DIR FILE RAW NUMBER EXT). +Internal variable. DIR is the directory part, FILE the file name +without directory part. FILE consists of its extension EXT, RAW and a +numbering NUMBER just in front of the extension. It is used by the +expansions DIR, FILE, FILE_SANS, FILE_EXT and others in +`template-expansion-alist'. Also useful for user defined functions in +`template-derivation-alist' and the per-template definition section.") + +(defvar template-modified nil + "Internal variable. Whether user is asked during the expansion process.") +(defvar template-secure t + "Internal variable. Whether all per-template definitions are secure.") +(defvar template-point-messages nil + "Internal variable. List of lines for temporary message at point.") +(defvar template-before-messages nil + "Internal variable. List of lines for temporary message before expansion.") +(defvar template-after-messages nil + "Internal variable. List of lines for temporary message after expansion.") + +(defvar template-point nil + "Internal variable. Position of point. Set with expansion form P.") +(defvar template-mark nil + "Internal variable. Position of mark. Set with expansion form M.") + +(defvar template-current nil + "Internal variable. Current key of expansion form.") +(defvar template-string-alist nil + "Internal variable. Alist of user inputs for `template-read'.") +(defvar template-register-alist nil + "Internal variable. Alist of used registers.") +(defvar template-local-alist nil + "Internal variable. Alist of per-template defined expansions.") + +(defvar template-ffap-file-finder nil + "Value used inside `template-ffap-find-file'. +If nil, initialize it to the value of `ffap-file-finder', i.e., this +variable holds the original value of that variable which will be set to +`template-ffap-find-file' in `template-initialize'.") + + +;;;=========================================================================== +;;; Functions: `find-file'/`insert-file-contents', hooking into `find-file' +;;;=========================================================================== + +(defun template-find-template (filename &optional replace) + "Switch to a buffer visiting template file FILENAME. +If optional REPLACE is non-nil, replace the current buffer contents with +the contents of file FILENAME. + +This function always considers template files as text files." + (let ((file-name-buffer-file-type-alist nil)) ; Emacs on DOS/NT + (if replace + (insert-file-contents filename nil nil nil + ;; 5th arg not t with empty accessible part + ;; (XEmacs bug workaround: would infloop) + (> (point-max) (point-min))) + (let ((template-auto-insert nil)) + (switch-to-buffer (find-file-noselect filename)))))) + +(defun template-not-found-function () + "Use a template when visiting a non-existent file. +See `template-auto-insert' and `template-find-file-commands'. Function +in `find-file-not-found-hooks'." + (and template-auto-insert (not buffer-read-only) (bobp) (eobp) + (or (memq this-command template-find-file-commands) + (and (memq this-command template-file-select-commands) + ;; thanks to Dave Love : + (memq (car-safe (car command-history)) + ;; To always include `find-file-at-point', use ffap + ;; initialization (see `template-ffap-find-file') + template-find-file-commands))) + (let ((template (cdr (template-derivation buffer-file-name t t)))) + (and template + (file-readable-p template) + (or (eq template-auto-insert t) + (y-or-n-p + (format "Use template %s? " + (cond-emacs-xemacs + (abbreviate-file-name template :XEMACS t))))) + (progn + (template-new-file nil template) + (setq this-command 'session-disable) + t))))) + +(defun template-ffap-find-file (filename) + "Function to use in `ffap-file-finder'. +Add an entry to `command-history' if necessary and call function in +`template-ffap-file-finder' with argument FILENAME." + (or (memq (car-safe (car command-history)) + '(ffap find-file-at-point)) + (setq command-history + (cons (list 'find-file-at-point filename) command-history))) + (if (eq template-ffap-file-finder 'template-ffap-find-file) + (find-file filename) + (funcall template-ffap-file-finder filename))) + + +;;;=========================================================================== +;;; Main function +;;;=========================================================================== + +(defun template-expand-template-interactive () + (let* ((use (template-derivation (expand-file-name + (or buffer-file-name "NONE")) + t)) + (tpl (read-file-name "Insert and expand template: " + (file-name-directory (cdr use)) + (file-name-nondirectory (cdr use)) + t + (file-name-nondirectory (cdr use))))) + (if (string= tpl "") + (error "No template file provided")) + (list (expand-file-name tpl (file-name-directory (cdr use)))))) + +;;;###autoload +(defun template-expand-template (template) + "Expand template file TEMPLATE and insert result in current buffer. +Using a template for inserting some text consists of: + 1. Template derivation: suggest a reasonable template file to the user + according to `buffer-file-name', see `template-derivation-alist'. + 2. Template insertion: insert the template file at point into the + current buffer. + 3.. as steps 6.. of `template-new-file'." + (interactive (template-expand-template-interactive)) + (save-restriction + (narrow-to-region (point) (point)) + (template-new-file nil template t))) + +(defun template-new-file-interactive () + "Interactive specification for `template-new-file'. +Return \(FILE TEMPLATE)." + (let* ((inp (read-file-name (if current-prefix-arg + "New file (+template, no name change): " + "New file (+template): ") + nil "")) + (use (cond ((equal inp "") + (error "Empty/no input")) + ((file-directory-p inp) + (error "%S is a directory" inp)) + (t (template-derivation (expand-file-name inp) + current-prefix-arg)))) + (tpl (read-file-name (format "File %s uses template: " + (file-name-nondirectory (car use))) + (file-name-directory (cdr use)) + (file-name-nondirectory (cdr use)) + t + (file-name-nondirectory (cdr use))))) + (list (car use) + (if (string= tpl "") + nil + (expand-file-name tpl (file-name-directory (cdr use))))))) + +;;;###autoload +(defun template-new-file (file template &optional with-undo) + "Open a new file FILE by using a TEMPLATE. +Using a template for creating a new file consists of, steps 1 to 3 are +only executed when called interactively: + 1. Prompt for the name of the new file. + 2. Template derivation: suggest a reasonable template file to the user + see `template-derivation-alist'. + 3. File name refinement: e.g., if the given file name is \"exercise\" + and there are two files \"exercise1.tex\" and \"exercise2.tex\" in + the same directory and if we have a template \"exercise.tex.tpl\", + the file name is refined to \"exercise3.tex\". This is turned off + when \\[template-new-file] is called with a prefix argument. + 4. Template insertion: insert the template file into the empty buffer. + 5. Read per-template expansion definition section starting at + `template-definition-start' and delete it. + 6. Display :before message in `template-message-buffer'. + 7. Execute pre-expansion commands defined in the definition section. + 8. Set local variables defined in the definition section. + 9. Expansion: expand the expansion forms (text matched by + `template-expansion-regexp') They are defined in the definition + section, in `template-expansion-alist', or provided by default, see + `template-expansion-regexp' and `template-register-regexp'. + 10. Execute post-expansion commands defined in the definition section. + 11. Run `normal-mode' and functions in `find-file-hooks'. + 12. Update header according to `template-update-header' with argument + `if-exists'. + 13. Display :after message in `template-message-buffer'. + 14. Report: display a temporary message at point defined in the + definition section and an automatically generated message in the + minibuffer area, see `template-message-timeout'. + +If optional WITH-UNDO is non-nil, store corresponding changes in +`buffer-undo-list'. If FILE is nil, the buffer for FILE has already +been created and the accessible part will be replaced by the expanded +template. If TEMPLATE is nil (empty input when called interactively), +do not use a template." + (interactive (template-new-file-interactive)) + ;; check template and file name -------------------------------------------- + (if template + (if (file-readable-p template) + (if (file-directory-p template) + (error "Template %s is a directory" template)) + (if (null (yes-or-no-p (format "Template %s does not exist. Create? " + template))) + (error "No template file to use") + (template-make-directory (file-name-directory template)) + (template-find-template template) + (error "You should create this template first")))) + (if (not file) + (switch-to-buffer (current-buffer)) + (and (or (get-file-buffer file) (file-exists-p file)) + (null (yes-or-no-p (format "File %s exists. Delete contents? " file))) + (error "Cannot use templates for existing files")) + (let ((auto-mode-alist nil) + (enable-local-variables nil) + (find-file-not-found-hooks nil) + (enable-local-eval nil)) + (switch-to-buffer (find-file-noselect file)))) + (when template + (or with-undo (setq buffer-undo-list t)) + (template-find-template template t) + (template-new-file-0 with-undo))) + +(defun template-new-file-0 (with-undo) + "Perform template replacements in current buffer. +If WITH-UNDO is non-nil, store corresponding changes in +`buffer-undo-list'." + ;; start replacement ------------------------------------------------------- + (or with-undo (set-buffer-modified-p nil)) + (goto-char (point-min)) + (setq template-secure t + template-point nil + template-mark nil + template-modified nil + template-point-messages nil + template-before-messages nil + template-after-messages nil + template-local-alist nil + template-register-alist nil + template-string-alist nil) + (let ((form-selector nil) + (pre-command-list nil) + (post-command-list nil) + (local-variable-list nil) + val) + ;; read per-template definition section ---------------------------------- + (goto-char (point-min)) + (when (re-search-forward + (concat "^[ \t]*" template-definition-start "[ \t]*$") nil t) + (condition-case () + (while t + (setq val (read (current-buffer))) + (cond (;; ("KEY" . xxx): ask user -------------------------------- + (and (consp val) (stringp (car val))) + (let* ((def (cdr val)) ; expansion forms + (msg (cond ((null template-message-prompt-format) + nil) + ((stringp def) def) + ((and (consp def) (stringp (car def))) + (car def))))) + (when msg ; list prompts in before-messages + (or template-before-messages + (null template-message-prompt-intro) + (push template-message-prompt-intro + template-before-messages)) + (push (format template-message-prompt-format msg) + template-before-messages)) + (push (cons (car val) (template-translate-definition def)) + template-local-alist))) + ;; :before, :after, :eval-before, :eval-after -------------- + ((null val) ; nil is deprecated + (setq form-selector + (cond ((null form-selector) :old-before) + ((eq form-selector :old-before) :old-after) + ((eq form-selector :old-after) + (error "More than two (obsolete) nil forms")) + (t + (error "Used obsolete nil form with new form selectors"))))) + ((memq val '(:before :after :eval-before :eval-after)) + (setq form-selector val)) + ;; "MESSAGE" ----------------------------------------------- + ((stringp val) + (cond ((eq form-selector :before) + (push val template-before-messages)) + ((eq form-selector :after) + (push val template-after-messages)) + (t + (push val template-point-messages)))) + ;; (CHAR . xxx): set register ------------------------------ + ((and (consp val) (template-char-or-char-int-p (car val))) + (let ((reg (template-char-or-int-to-char (car val)))) + (if (atom (cdr val)) + (set-register reg (cdr val)) + (set-register reg (cadr val)) + (when template-message-register-format + (let ((msg (format template-message-register-format + reg (cadr val) + (or (caddr val) "")))) + (if template-message-buffer + (progn + (if template-before-messages + (push msg template-before-messages)) + (or template-after-messages + (null template-message-register-intro) + (push template-message-register-intro + template-after-messages)) + (push msg template-after-messages)) + (push msg template-point-messages))))))) + ;; set var, execute command and sexpr ---------------------- + ((and (memq form-selector '(nil :before :after)) + (consp val) + (symbolp (car val))) + (or (and (functionp (get (car val) 'template-secure-value)) + (funcall (get (car val) 'template-secure-value) + (cdr val))) + (setq template-secure nil)) + (push val local-variable-list)) + ((memq form-selector '(:eval-before :old-before)) + (push (template-elisp-in-definition val) + pre-command-list)) + ((memq form-selector '(:eval-after :old-after)) + (push (template-elisp-in-definition val) + post-command-list)) + (t + (error "Illegal form")))) + (error nil)) + (skip-chars-forward " \t\n\f") + (or (eobp) + (error "Invalid definition in line %d (pos %d) of the template file" + (count-lines 1 (point)) (point))) + (or template-secure + (null (default-value template-confirm-insecure)) + (y-or-n-p "Have you checked the template functions? ") + (error "Failed security check")) + (delete-region (match-beginning 0) (point-max))) + ;; expand ---------------------------------------------------------------- + (template-display-messages template-before-messages) + (eval (cons 'progn (nreverse pre-command-list))) + (while local-variable-list + (make-local-variable (caar local-variable-list)) + (set (caar local-variable-list) (cdar local-variable-list)) + (setq local-variable-list (cdr local-variable-list))) + (goto-char (point-min)) + (while (re-search-forward template-expansion-regexp nil t) + (setq template-current (buffer-substring (match-beginning 1) + (match-end 1)) + val (assoc template-current template-local-alist)) + (unless val + (if (setq val (assoc template-current template-key-alias-alist)) + (setq template-current (cdr val))) + (setq val (or (assoc template-current template-expansion-alist) + (assoc template-current + template-default-expansion-alist)))) + (delete-region (match-beginning 0) (match-end 0)) + (cond (val + (eval (cons 'progn (cdr val)))) + ((string-match template-register-regexp template-current) + (template-register)) + (t + (template-read (format "Replacement for `%s': " + template-current))))) + (eval (cons 'progn (nreverse post-command-list))) + (save-restriction + (widen) + (normal-mode t) + (or with-undo (template-update-header 'if-exists)) + (run-hooks 'find-file-hooks)) + ;; message --------------------------------------------------------------- + (template-display-messages template-after-messages) + (cond ((null template-register-alist) + (message "%s, no buffer location in register" + (if template-mark "Mark set" "No mark"))) + (t (message "%s, buffer location in register: %s" + (if template-mark "Mark set" "No mark") + (mapconcat (function + (lambda (x) + (if (cdr x) + (concat (char-to-string (car x)) "*") + (char-to-string (car x))))) + (nreverse template-register-alist) + ", ")))) + (or with-undo (set-buffer-modified-p template-modified)) + (goto-char (point-min)) + (when template-point + (goto-char template-point) + (set-marker template-point nil)) + (when template-mark + (push-mark template-mark) + (set-marker template-mark nil) + (if (fboundp 'zmacs-activate-region) (zmacs-activate-region))) + (when (and template-point-messages + (or (cdr template-point-messages) + (not (string-equal (car template-point-messages) "")))) + (let ((beg (point)) + end) + (if (cdr template-point-messages) + (insert (mapconcat 'identity + (nreverse template-point-messages) + "\n") + "\n") + (insert (car template-point-messages))) + (setq end (point)) + (goto-char beg) + (and (fboundp 'make-extent) (fboundp 'set-extent-face) + (set-extent-face (make-extent beg end) 'template-message-face)) + (recenter) + (sit-for template-message-timeout) + (delete-region beg end)))) + (recenter) + (unless with-undo + (setq buffer-undo-list nil) + (set-buffer-modified-p template-modified))) + +(defun template-display-messages (messages) + (when (and messages template-message-buffer) + (setq messages (nreverse messages)) + (with-output-to-temp-buffer template-message-buffer + (while messages + (princ (pop messages)) + (if messages (princ "\n")))))) + + +;;;=========================================================================== +;;; Determine name of the new file and the template +;;;=========================================================================== + +(defun template-derivation (full arg &optional no-default) + "Derive template file name and do file name refinement. +Return (REFINED . TEMPLATE) where REFINED is the refined version of FULL +and TEMPLATE and template file name, see `template-derivation-alist'. +FULL is the initial file name given by the user. File name refinement +is turned off when ARG is non-nil. If optional argument NO-DEFAULT is +non-nil, return nil instead (FULL \. \"~/.templates/DEFAULT.tpl\") if no +matching entry can be found in `template-derivation-alist'." + ;; Get all templates ------------------------------------------------------- + (setq template-all-templates nil) + (let* ((dir (file-name-directory full)) + (len (length dir)) + (case-fold-search (memq system-type '(vax-vms ms-dos windows-nt)))) + (while (and dir + (not (and template-stop-derivation + (fboundp template-stop-derivation) + (funcall template-stop-derivation dir)))) + (template-all-templates template-subdirectories dir) + (setq dir (file-name-directory (directory-file-name dir))) + (or (> len (setq len (length dir))) + (setq dir nil))) + (template-all-templates template-default-directories) + (setq template-all-templates (nreverse template-all-templates))) + ;; Get template file ------------------------------------------------------- + (if (string= (file-name-nondirectory full) "") + (error "You cannot use templates for directories")) + (setq template-file (template-split-filename full)) + (let ((tests template-derivation-alist) + test template file) + (while tests + (setq test (caar tests) + file (cdar tests)) + (if (setq template + (if (functionp (car test)) + (apply (car test) (cdr test)) + (apply 'template-default-template test))) + (setq tests nil) + (setq tests (cdr tests)))) + (if template + (or arg + (if (functionp (car file)) + (apply (car file) template (cdr file)) + (apply 'template-unique-file template file))) + (or no-default + (setq template (template-split-filename + "DEFAULT" + (template-default-directory))))) + (if template + (cons (expand-file-name (cadr template-file) (car template-file)) + (expand-file-name (concat (cadr template) template-extension) + (car template)))))) + +(defun template-default-directory () + "Return directory of file \"DEFAULT.tpl\"." + (let ((dirs template-default-directories) + (name (concat "DEFAULT" template-extension)) + dir) + (while dirs + (setq dir (pop dirs)) + (if (file-readable-p (expand-file-name name dir)) + (setq dirs nil) + (setq dir nil))) + (or dir + (car template-default-directories) + (expand-file-name "~/.templates/")))) + + +;;;=========================================================================== +;;; Small functions +;;;=========================================================================== + +(defun template-make-directory (dir) + "Create DIR if it does not exists yet." + (cond ((file-exists-p dir)) + ((yes-or-no-p (format "The directory %s does not exist. Create? " dir)) + (make-directory dir t)) + (t (error "You should create a directory \"%s\"" dir))) + dir) + +(defun template-split-filename (file &optional dir) + "Split file name into its parts. +If DIR is nil, FILE is a fully expanded file name, otherwise FILE is a +file name without its directory part DIR. See `template-file'." + (or dir (setq dir (template-make-directory (file-name-directory file)) + file (file-name-nondirectory file))) + (let* ((ext (string-match "\\.[^.]*\\'" file)) + (raw (substring file 0 ext)) + (num (string-match "[^0-9][0-9]+\\'" raw))) + (if num + (list dir file + (substring raw 0 (1+ num)) + (substring raw (1+ num)) + (if ext (substring file ext) "")) + (list dir file raw "" (if ext (substring file ext) ""))))) + +(defun template-translate-definition (def) + "Translate DEF of expansion and set `template-secure' accordingly." + (cond ((null def) ; zero form + nil) + ((template-char-or-char-int-p def) + `((template-register ,def))) + ((stringp def) + `((template-read ,def nil nil nil t))) + ((symbolp def) + `((insert (if (stringp ,def) ,def template-string-default)))) + ((and (consp def) (stringp (car def))) + (if (consp (car-safe (cdr def))) + `((template-choice ,(car def) (quote ,(cdr def)))) + `((apply (quote template-read) (quote ,def))))) + ((consp (car-safe def)) + (setq template-secure nil) + def) + (t + (list (template-elisp-in-definition (car def) (cdr def)))))) + +(defun template-elisp-in-definition (def &optional prefix) + "Return valid elisp definition and set `template-secure' accordingly. +DEF is the elisp form, PREFIX would be the prefix argument if DEF is a +command." + (cond ((consp def) + (setq template-secure nil) + def) + ((or (symbolp def) (vectorp def)) + (or (and (symbolp def) (get def 'template-secure-command)) + (setq template-secure nil)) + (if (and (symbolp def) + (functionp (get def 'template-secure-command)) + (listp prefix) + (funcall (get def 'template-secure-command) prefix)) + `(apply (quote ,def) (quote ,prefix)) + `(progn (setq prefix-arg (quote ,prefix)) + (command-execute (quote ,def))))) + (t + (error "Illegal form")))) + + +;;;=========================================================================== +;;; Compute template name +;;;=========================================================================== + +(defun template-all-templates (dirs &optional base) + "Read names of template files in DIRS relatively to BASE. +Insert the names to internal variable `template-all-templates'." + (let ((regexp (concat (regexp-quote template-extension) "\\'")) + (endpos (- (length template-extension))) + dir templates) + (while dirs + (setq dir (expand-file-name (car dirs) base) + dirs (cdr dirs)) + (cond-emacs-xemacs + (and (file-accessible-directory-p dir) + (file-readable-p dir) + (setq templates (directory-files dir t regexp :XEMACS nil t)) + (while templates + (and :EMACS + (not (file-directory-p (car templates))) + :BOTH + (file-readable-p (car templates)) + (push (template-split-filename (substring (car templates) + 0 + endpos)) + template-all-templates)) + (setq templates (cdr templates)))))))) + +(defun template-set-template-part (part file-part) + "Set template part according to definition PART and FILE-PART. +See `template-derivation-alist' for details." + (when part + (cond ((stringp part) part) + ((eq part t) file-part) + ((null (string= file-part "")) file-part)))) + +(defun template-default-template (&optional raw num ext regexp) + "Return template according to RAW, NUM, EXT and REGEXP. +See `template-derivation-alist' for details." + (if (or (null regexp) (string-match regexp (cadr template-file))) + (let ((templates template-all-templates) + (file-rne (cddr template-file)) + result template-rne) + (setq raw (template-set-template-part raw (car file-rne)) + num (template-set-template-part num (cadr file-rne)) + ext (template-set-template-part ext (caddr file-rne))) + (while templates + (setq template-rne (cddar templates)) + (if (and (or (null raw) (string= (car template-rne) raw)) + (or (null num) (string= (cadr template-rne) num)) + (or (null ext) (string= (caddr template-rne) ext))) + (setq result (car templates) + templates nil) + (setq templates (cdr templates)))) + result))) + + +;;;=========================================================================== +;;; File name refinement +;;;=========================================================================== + +(defun template-default-file (template &optional raw num ext) + "Refine file name according to TEMPLATE, RAW, NUM and EXT. +The result is in `template-file'. See `template-derivation-alist'." + (let ((template-rne (cddr template)) + (file-rne (cddr template-file))) + (if raw + (if (eq raw t) (setq raw (car template-rne))) + (setq raw (car file-rne))) + (if num + (if (eq num t) (setq num (cadr template-rne))) + (setq num (cadr file-rne))) + (if ext + (if (eq ext t) (setq ext (caddr template-rne))) + (setq ext (caddr file-rne))) + (setcdr template-file (list (concat raw num ext) raw num ext)))) + +(defunx template-unique-file (template &optional raw num ext auto-num) + "Refine file name according to TEMPLATE, RAW, NUM, EXT and AUTO-NUM. +Use auto numbering if NUM is not \"\" or AUTO-NUM is non-nil. The +result is in `template-file'. See `template-derivation-alist'." + (template-default-file template raw num ext) + (let* ((dir (car template-file)) + (full (expand-file-name (cadr template-file) dir))) + (when (if (string= (fourth template-file) "") + auto-num + (setq auto-num + (and (or (get-file-buffer full) + (file-readable-p full)) + (string-to-int (fourth template-file))))) + (setq auto-num (1- auto-num) + raw (third template-file) + ext (fifth template-file)) + (let ((list (buffer-list)) + file1 dir1) + (while list + (and (setq file1 (buffer-file-name (car list))) + (setq dir1 (file-name-directory file1)) + (string= dir1 dir) + (setq auto-num + (max (template-filename-number + (cddr (template-split-filename + (file-name-nondirectory file1) + dir1)) + raw ext) + auto-num))) + (setq list (cdr list))) + (setq list (directory-files dir nil nil t :XEMACS t)) + (while list + (unless (:EMACS file-directory-p (car list)) + (setq auto-num + (max (template-filename-number + (cddr (template-split-filename (car list) dir)) + raw ext) + auto-num) + list (cdr list)))) + (template-default-file template raw + (int-to-string (1+ auto-num)) + ext))))) + +(defun template-filename-number (file-rne raw ext) + "Return numbering in FILE-RNE if the RAW and EXT parts are equal." + (or (and (string= (car file-rne) raw) + (string= (caddr file-rne) ext) + (string-to-int (cadr file-rne))) + 0)) + + +;;;=========================================================================== +;;; Safe commands for per-template expansions +;;;=========================================================================== + +(defun template-insert-time (&optional format default) + "Insert time into current buffer using time format FORMAT. +If FORMAT is not a string, it uses DEFAULT or `current-time-string'." + (interactive) + (insert (if (and (stringp format) (fboundp 'format-time-string)) + (format-time-string format (current-time)) + (or default (current-time-string))))) +(put 'template-insert-time 'template-secure-command + (lambda (args) + (or (null args) (and (stringp (car args)) (null (cdr args)))))) + + +;;;=========================================================================== +;;; Functions for the predefined expansions +;;;=========================================================================== + +(defun template-register (&optional register) + "Set current location in register REGISTER. +That is, \\[jump-to-register] REGISTER jumps to the current position. +If REGISTER is nil, use register corresponding to the last character in +`template-current'." + (let* ((char (if register + (template-char-or-int-to-char register) + (aref template-current (1- (length template-current))))) + (elem (assoc char template-register-alist))) + (point-to-register char) + (if elem + (setcdr elem t) + (push (list char) template-register-alist)))) + +(defun template-read (prompt &optional prefix suffix default again-p) + "Ask user with PROMPT for a STRING to be inserted. +If STRING is not \"\", insert PREFIX STRING SUFFIX, otherwise DEFAULT. +If AGAIN-P is nil, do not ask if `template-current' appears another time +as key in a expansion form. If AGAIN-P is `expand', the inserted region +is searched for expansion forms where STRING is marked as a literal +environment, see `template-literal-environment'." + (setq template-modified t) + (let ((pos (point)) + (elem (and (null again-p) + (assoc template-current template-string-alist)))) + (if elem + (setq elem (cdr elem)) + (setq elem (read-from-minibuffer prompt nil nil nil + 'template-history) + elem (cond ((string= elem "") (or default "")) + ((eq again-p 'expand) + (concat prefix + (format template-expansion-format + (car template-literal-environment)) + elem + (format template-expansion-format + (cdr template-literal-environment)) + suffix + (format template-expansion-format + (car template-literal-environment)) + (format template-expansion-format + (cdr template-literal-environment)))) + (t + (concat prefix elem suffix)))) + (or again-p (push (cons template-current elem) template-string-alist))) + (insert elem) + (if (eq again-p 'expand) (goto-char pos)))) + +(defun template-choice (prompt table) + "Ask user with PROMPT for a choice and insert it. +Each element in TABLE looks like (ANSWER . TEXT). Ask for an input with +completion over all ANSWERs and insert corresponding TEXT if ANSWER is a +string, otherwise ask a \"y or n\" question and use the result of +`y-or-n-p' as ANSWER. Expansion forms in TEXT will be expanded." + (setq template-modified t) + (let ((pos (point))) + (insert (or (cdr (assoc (if (stringp (caar table)) + (completing-read prompt table nil t nil + 'template-choice-history) + (y-or-n-p prompt)) + table)) + "") + (format template-expansion-format + (car template-literal-environment)) + (format template-expansion-format + (cdr template-literal-environment))) + (goto-char pos))) + + +;;;=========================================================================== +;;; Menu filter +;;;=========================================================================== + +(defun template-menu-filter (menu-items) + ;; checkdoc-params: (menu-items) + "Menu filter for `template-creation-menu'." + (let ((alist (append template-expansion-alist + template-default-expansion-alist)) + menu used key) + (while alist + (unless (member (setq key (car (pop alist))) used) + (push key used) + (push (vector (concat "Insert " key) + (list 'template-insert-form current-prefix-arg key) + t) + menu))) + (append menu-items (nreverse menu)))) + + +;;;=========================================================================== +;;; Insert and define forms +;;;=========================================================================== + +(defun template-buffer-template-p () + "Return non-nil, if current buffer is likely to be a template file." + (and buffer-file-name + (string-match (concat (regexp-quote template-extension) "\\'") + (file-name-sans-versions buffer-file-name)))) + +(defun template-open-template () + "If current buffer is no template file, open a new one." + (interactive) + (if (template-buffer-template-p) + (barf-if-buffer-read-only) + (let (name + (dir (and (car template-subdirectories) + (expand-file-name (car template-subdirectories))))) + (if (null buffer-file-name) + (setq name (concat "TEMPLATE" template-extension)) + (setq name (file-name-sans-versions + (file-name-nondirectory buffer-file-name))) + (if (string-match ".\\.[^.]*\\'" name) + (setq name (concat "TEMPLATE" + (substring name (1+ (match-beginning 0))) + template-extension)) + (setq name (concat name template-extension) + ;; dot file => template not specific for directory + dir (car template-default-directories)))) + (setq name (read-file-name "Open template file (empty=none): " + dir nil nil name)) + (or (string= name "") + (template-find-template name))))) + +(defun template-insert-form (arg key) + "Insert an expansion form according to KEY into template. +When called interactively, allow completion over all keys in +`template-expansion-alist' and `template-default-expansion-alist'. +If prefix ARG is nil, run `template-open-template' first." + (interactive + (list current-prefix-arg + (completing-read "Insert key (0-9 for register position): " + (append template-expansion-alist + template-default-expansion-alist)))) + (or arg (template-open-template)) + (insert (format template-expansion-format key)) + (if (equal key (car template-literal-environment)) + (let ((pos (point))) + (insert (format template-expansion-format + (cdr template-literal-environment))) + (goto-char pos)))) + +(defun template-define-start (arg &rest args) + "Insert a definition section and definition into template. +See `template-definition-start'. If ARGS is non-nil, pass ARGS to +`format' for a new definition. If prefix ARG is nil, run +`template-open-template' first." + (interactive "P") + (or arg (template-open-template)) + (save-excursion + (goto-char (point-min)) + (unless (re-search-forward (concat "^[ \t]*" + template-definition-start + "[ \t]*$") nil t) + (goto-char (point-max)) + (or (bolp) (insert "\n")) + (insert template-definition-start)) + (goto-char (point-max)) + (or (bolp) (insert "\n")) + (if args (insert (apply 'format args) "\n"))) + (message "Put definition at the end of the template")) + +(defun template-define-message (arg message) + "Insert a temporary message MESSAGE definition into template. +For ARG, see `template-define-start'." + (interactive "P\nsTemporary message: ") + (template-define-start arg "%S" message)) + +(defun template-define-prompt (arg key prompt &optional prefix suffix default) + "Insert a definition for KEY as PROMPT into template. +For ARG, see `template-define-start'." + (interactive "P\nsExpansion key: \nsExpansion prompt: \nsPrefix for non-empty input: \nsSuffix for non-empty input: \nsDefault for empty input: ") + (template-define-start arg "(%S %S %S %S %S)" + key prompt prefix suffix default)) + +(defun template-define-register (arg register) + "Insert a setting of REGISTER into template. +For ARG, see `template-define-start'." + (interactive "P\ncDefine register: ") + (let* ((old (get-register register)) + (contents (read-from-minibuffer "Register contents: " + (and (stringp old) + (not (string-match "\n" old)) + old))) + (comment (read-from-minibuffer "Comment (empty=none): "))) + (if (string= comment "") + (template-define-start arg "(%S %S)" register contents) + (template-define-start arg "(%S %S %S)" register contents comment)))) + + +;;;=========================================================================== +;;; Initialization +;;;=========================================================================== + +;; easymenu.el is for top-level menus only... +(defunx template-add-submenu (menu &optional where) + "Add the submenu MENU to the end of a menu in WHERE in the menubar. +WHERE is a list of menus tried to add MENU to. If no such menu exist, +no menu is added. When using Emacs, always add to the \"Edit\" menu. +See `easy-menu-define' for the format of MENU." + (and menu + :EMACS + (>= emacs-major-version 21) + (boundp 'menu-bar-edit-menu) + (let ((keymap (easy-menu-create-menu (car menu) (cdr menu)))) + ;; `easy-menu-get-map' doesn't get the right one => use hard-coded + (define-key-after menu-bar-edit-menu (vector (intern (car menu))) + (cons 'menu-item + (cons (car menu) + (if (not (symbolp keymap)) + (list keymap) + (cons (symbol-function keymap) + (get keymap 'menu-prop))))))) + :XEMACS + (featurep 'menubar) + (let ((current-menubar default-menubar) path) + (while where + (setq path (list (pop where))) + (if (find-menu-item default-menubar path) + (setq where nil) + (setq path nil))) + (when path (add-submenu path menu))))) + +;;;###autoload +(defunx template-initialize (&rest dummies) + ;; checkdoc-params: (dummies) + "Initialized package template. See variable `template-initialize'." + (interactive) + (setq template-use-package t) + (let ((regexp (concat (regexp-quote template-extension) "\\'"))) + (or (assoc regexp auto-mode-alist) + (push (list regexp nil 'template-new-file) auto-mode-alist))) + (when (or (eq template-initialize t) + (memq 'cc-mode template-initialize)) + (add-hook 'c-mode-common-hook 'template-c-init-fill-function) + (add-hook 'antlr-mode-hook 'template-c-init-fill-function)) + (when (or (eq template-initialize t) + (memq 'de-html-helper template-initialize)) + (setq html-helper-build-new-buffer nil) + (setq html-helper-do-write-file-hooks nil)) + (when (or (eq template-initialize t) + (memq 'keys template-initialize)) + (condition-case nil ; older Emacses don't understand all + (progn + (define-key ctl-x-map "t" 'template-new-file) + (define-key ctl-x-map [(control =)] 'template-single-comment) + (define-key ctl-x-map [(control ?\;)] 'template-block-comment)) + (error nil))) + (when (or (eq template-initialize t) + (memq 'menus template-initialize)) + (template-add-submenu template-comment-menu :XEMACS '("Edit")) + (template-add-submenu template-creation-menu :XEMACS '("Cmds" "Edit")) + :EMACS + (and (boundp 'menu-bar-files-menu) + (define-key-after menu-bar-files-menu [template-new-file] + '(menu-item "New File Using Template..." template-new-file + :enable (not (window-minibuffer-p + (frame-selected-window + menu-updating-frame))) + :help "Create a new file, using a template") + 'dired)) + :XEMACS + (and (featurep 'menubar) + (find-menu-item default-menubar '("File")) + (let ((current-menubar default-menubar)) + ;; XEmacs-20.4 `add-submenu' does not have 4th arg IN-MENU + (add-menu-button '("File") + ["New File Using Template..." template-new-file + :active t] + "Insert File...")))) + (if (and (boundp 'init-file-loaded) init-file-loaded) + ;; doesn't exist in Emacs + (template-after-init) + (add-hook 'after-init-hook 'template-after-init t))) + +(defun template-after-init () + "Late initialization for package template. +See function and variable `template-initialize'." + (when (or (eq template-initialize t) + (memq 'auto template-initialize)) + (add-hook 'write-file-hooks 'template-update-buffer) + (add-hook 'find-file-not-found-hooks 'template-not-found-function t)) + (when (or (eq template-initialize t) + (memq 'ffap template-initialize)) + (or template-ffap-file-finder + (setq template-ffap-file-finder + (if (boundp 'ffap-file-finder) + ffap-file-finder + (or (get 'ffap-file-finder 'saved-value) 'find-file)))) + (setq ffap-file-finder 'template-ffap-find-file))) + +;;; Local IspellPersDict: .ispell_template +;;; template.el ends here diff --git a/template.elc b/template.elc new file mode 100644 index 0000000000000000000000000000000000000000..770cbaa7c7fd7b573db438641a110405ebeb09fc GIT binary patch literal 82069 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 Vjoe##JH9kVDPdZ>c-L9D+h3wGe^3Ab literal 0 HcmV?d00001 diff --git a/templates/DEFAULT.tpl b/templates/DEFAULT.tpl new file mode 100644 index 00000000..4ac7cfed --- /dev/null +++ b/templates/DEFAULT.tpl @@ -0,0 +1,3 @@ +### DEFAULT.tpl --- (>>>POINT<<<) + + diff --git a/templates/Makefile.tpl b/templates/Makefile.tpl new file mode 100644 index 00000000..8bb58753 --- /dev/null +++ b/templates/Makefile.tpl @@ -0,0 +1,9 @@ +### Makefile.tpl --- (>>>POINT<<<) + +## Author: (>>>AUTHOR<<<) +## Version: $Id: (>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp $ +## Keywords: (>>>1<<<) +## X-URL: (>>>2<<<) + + +### (>>>FILE<<<) ends here diff --git a/templates/README.tpl b/templates/README.tpl new file mode 100644 index 00000000..56d28139 --- /dev/null +++ b/templates/README.tpl @@ -0,0 +1,11 @@ +### README.tpl --- (>>>POINT<<<)(>>>DIR<<<) + +## Copyright (>>>YEAR<<<) (>>>USER_NAME<<<) +## +## Author: (>>>AUTHOR<<<) +## Keywords: (>>>1<<<) + + + + + diff --git a/templates/TEMPLATE.c.tpl b/templates/TEMPLATE.c.tpl new file mode 100644 index 00000000..b76fe7d0 --- /dev/null +++ b/templates/TEMPLATE.c.tpl @@ -0,0 +1,7 @@ +/* @(#)TEMPLATE.c.tpl + */ + +#include +#include "(>>>FILE_SANS<<<).h" + +(>>>POINT<<<) diff --git a/templates/TEMPLATE.cls.tpl b/templates/TEMPLATE.cls.tpl new file mode 100644 index 00000000..ed687637 --- /dev/null +++ b/templates/TEMPLATE.cls.tpl @@ -0,0 +1,47 @@ +%%% TEMPLATE.cls.tpl --- (>>>COMMENT<<<) + +%% Author: (>>>AUTHOR<<<) +%% Version: $Id: (>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp $ + +%%% Commentary: + +%% (>>>1<<<) + +%% Put this file into your TEXINPUTS. A typical document looks like: +%% \documentclass[OPTIONS]{(>>>FILE_SANS<<<)} +%% \begin{document} +%% (>>>2<<<) +%% \end{document} + +%% OPTIONS defaults to (>>>3<<<) + +%%% Code: + +\NeedsTeXFormat{LaTeX2e}(>>>POINT<<<)[1995/12/01] +\def\@rcs@ $#1Date: #2 #3$$#4Revision: #5$ { + \ProvidesPackage{(>>>FILE_SANS<<<)}[#2 v#5(>>>COMMENT<<<)]} +\@rcs@ $Date: (>>>VC_DATE<<<) $$Revision: 0.0 $ + +\DeclareOption{(>>>4<<<)}{%%% + } + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} +\ExecuteOptions{(>>>5<<<)} +\ProcessOptions +\LoadClass[a4paper]{article} + + + +%%%%########################################################################## +%%%% Main code +%%%%########################################################################## + +(>>>6<<<) + + +\endinput + +%%% Local Variables: +%%% TeX-auto-save: nil +%%% TeX-auto-parse-length: 99999 +%%% End: diff --git a/templates/TEMPLATE.el.tpl b/templates/TEMPLATE.el.tpl new file mode 100644 index 00000000..aba764c8 --- /dev/null +++ b/templates/TEMPLATE.el.tpl @@ -0,0 +1,47 @@ +;;; TEMPLATE.el.tpl --- (>>>POINT<<<) + +;; Copyright (>>>YEAR<<<) (>>>USER_NAME<<<) +;; +;; Author: (>>>AUTHOR<<<) +;; Version: $Id: (>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp $ +;; Keywords: (>>>1<<<) +;; X-URL: not distributed yet + +;; This program 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 program 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 this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;; (>>>2<<<) + +;; Put this file into your load-path and the following into your ~/.emacs: +;; (require '(>>>FILE_SANS<<<)) + +;;; Code: + +(provide '(>>>FILE_SANS<<<)) +(eval-when-compile + (require 'cl)) + + + +;;;;########################################################################## +;;;; User Options, Variables +;;;;########################################################################## + + +(>>>3<<<) + + +;;; (>>>FILE<<<) ends here diff --git a/templates/TEMPLATE.h.tpl b/templates/TEMPLATE.h.tpl new file mode 100644 index 00000000..fb72812d --- /dev/null +++ b/templates/TEMPLATE.h.tpl @@ -0,0 +1,10 @@ +/* @(#)TEMPLATE.h.tpl + */ + +#ifndef _(>>>FILE_UPCASE<<<)_H +#define _(>>>FILE_UPCASE<<<)_H 1 + +(>>>POINT<<<) + +#endif /* _(>>>FILE_UPCASE<<<)_H */ + diff --git a/templates/TEMPLATE.html.tpl b/templates/TEMPLATE.html.tpl new file mode 100644 index 00000000..5ead1e16 --- /dev/null +++ b/templates/TEMPLATE.html.tpl @@ -0,0 +1,21 @@ + + + + (>>>title<<<) + + + + +

(>>>title<<<)

+ + (>>>POINT<<<) + +
+
+ (>>>USER_NAME<<<), + (>>>DATE<<<) +
+ + +>>>TEMPLATE-DEFINITION-SECTION<<< +("title" "Document Title: ") diff --git a/templates/TEMPLATE.java.tpl b/templates/TEMPLATE.java.tpl new file mode 100644 index 00000000..ba485965 --- /dev/null +++ b/templates/TEMPLATE.java.tpl @@ -0,0 +1,16 @@ +/* @(#)TEMPLATE.java.tpl + */ +/** + * (>>>POINT<<<) + * + * @author (>>>USER_NAME<<<) + */ + +public class (>>>FILE_SANS<<<) +{ + (>>>1<<<) +} +>>>TEMPLATE-DEFINITION-SECTION<<< +"Template defines 2 registers (message disappears with first user event):" +(?m "public static void main(String[] argv)") +(?p "System.out.println(") diff --git a/templates/TEMPLATE.pl.tpl b/templates/TEMPLATE.pl.tpl new file mode 100644 index 00000000..a9e2dbd8 --- /dev/null +++ b/templates/TEMPLATE.pl.tpl @@ -0,0 +1,48 @@ +#!/usr/bin/perl +use strict; +use warnings; + +=head1 NAME + +=head1 DESCRIPTION + +=head1 SYNOPSIS + +=head1 SUBS + +=head2 main + +sub main { + my ( $help, $man ); + + my $result = GetOptions ( + "help|h" => \$help, + "verbose|v" => \$verbose, + "man|m" => \$man + ); + + if ( $man ) { pod2usage( -verbose => 2 ); } + + if ( ! ( $server ) || $help ) + { + pod2usage(1); + } + + +} + +main(); + +=head1 AUTHOR + + +(>>>USER_NAME<<<) <(>>>AUTHOR<<<)> + +=head1 LICENSE + +This program is free software, you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +1; diff --git a/templates/TEMPLATE.sh.tpl b/templates/TEMPLATE.sh.tpl new file mode 100644 index 00000000..228a86a7 --- /dev/null +++ b/templates/TEMPLATE.sh.tpl @@ -0,0 +1,2 @@ +#!/bin/bash +# (>>>USER_NAME<<<) <(>>>AUTHOR<<<)> diff --git a/templates/TEMPLATE.sty.tpl b/templates/TEMPLATE.sty.tpl new file mode 100644 index 00000000..d6e818c0 --- /dev/null +++ b/templates/TEMPLATE.sty.tpl @@ -0,0 +1,43 @@ +%%% TEMPLATE.sty.tpl --- (>>>COMMENT<<<) + +%% Author: (>>>AUTHOR<<<) +%% Version: $Id: (>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp $ + +%%% Commentary: + +%% (>>>1<<<) + +%% Put this file into your TEXINPUTS and the following into your preamble: +%% \usepackage[OPTIONS]{(>>>FILE_SANS<<<)} + +%% OPTIONS defaults to (>>>3<<<) + +%%% Code: + +\NeedsTeXFormat{LaTeX2e}(>>>POINT<<<)[1995/12/01] +\def\@rcs@ $#1Date: #2 #3$$#4Revision: #5$ { + \ProvidesPackage{(>>>FILE_SANS<<<)}[#2 v#5(>>>COMMENT<<<)]} +\@rcs@ $Date: (>>>VC_DATE<<<) $$Revision: 0.0 $ + +\DeclareOption{(>>>4<<<)}{%%% + } + +%%\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{(>>>9<<<)}} +\ExecuteOptions{(>>>5<<<)} +\ProcessOptions + + + +%%%%########################################################################## +%%%% Main code +%%%%########################################################################## + +(>>>6<<<) + + +\endinput + +%%% Local Variables: +%%% TeX-auto-save: nil +%%% TeX-auto-parse-length: 99999 +%%% End: diff --git a/templates/TEMPLATE.tex.tpl b/templates/TEMPLATE.tex.tpl new file mode 100644 index 00000000..d11ac867 --- /dev/null +++ b/templates/TEMPLATE.tex.tpl @@ -0,0 +1,24 @@ +%%% TEMPLATE.tex.tpl --- (>>>POINT<<<) + +%% Author: (>>>AUTHOR<<<) +%% Version: $Id: (>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp$ + + +\documentclass[12pt,draft,a4paper]{article} +%%\usepackage[debugshow,final]{graphics} + +%%\revision$Header: (>>>DIR<<<)(>>>FILE<<<),v 0.0 (>>>VC_DATE<<<) (>>>LOGIN_NAME<<<) Exp$ + +\begin{document} + + +%%%%########################################################################## + +\section{(>>>1<<<)} + + + + +%%%%########################################################################## + +\end{document} diff --git a/xemacs-bg.xpm b/xemacs-bg.xpm new file mode 100644 index 00000000..b0f21134 --- /dev/null +++ b/xemacs-bg.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char * xemacs_bg_xpm[] = { +"204 32 3 1", +" c None", +". c #E1F4E1", +"+ c #DDDDDD", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"............................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"}; diff --git a/xemacs-packages/etc/bbdb/bbdb-213-310.el b/xemacs-packages/etc/bbdb/bbdb-213-310.el new file mode 100644 index 00000000..5a791a50 --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-213-310.el @@ -0,0 +1,57 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; The 213 area code (in LA) has been split into 213 and 310. This code +;;; will map over your Insidious Big Brother Database and convert the area +;;; codes when approriate. It then displays the records which it has changed. +;;; +;;; This is derived from a list posted by Paul Eggert +;;; on 3 Mar 92 18:24:04 GMT. + +(require 'bbdb) + +(defconst bbdb-310-exchanges + '(201 202 203 204 205 206 207 208 209 210 212 214 215 216 217 218 219 220 + 246 247 270 271 273 274 275 276 277 278 279 280 281 282 284 285 286 287 + 288 289 297 301 302 305 306 312 313 314 315 316 317 318 319 320 322 323 + 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 348 350 352 + 354 355 363 364 370 371 372 373 374 375 376 377 378 379 390 391 392 393 + 394 395 396 397 398 399 401 402 403 404 406 407 408 409 410 412 414 416 + 417 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 + 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 + 454 455 456 457 458 459 470 471 472 473 474 475 476 477 478 479 490 491 + 492 493 494 495 496 497 498 499 501 502 510 512 513 514 515 516 517 518 + 519 521 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 + 540 541 542 543 544 545 546 547 548 549 550 551 552 553 556 557 558 559 + 568 570 571 572 573 574 575 576 577 578 590 591 592 593 594 595 596 597 + 598 599 601 602 603 604 605 606 607 608 609 615 616 618 630 631 632 633 + 634 635 637 638 639 640 641 642 643 644 645 646 647 648 649 652 657 659 + 670 671 672 673 674 675 676 677 679 690 691 692 693 694 695 696 697 698 + 699 708 715 719 761 762 763 764 767 768 769 781 782 783 784 785 787 788 + 791 792 793 794 795 796 797 798 799 800 801 802 803 804 806 807 809 812 + 813 814 815 816 819 820 821 822 823 824 825 826 827 828 829 830 831 832 + 833 834 835 836 837 838 839 840 841 842 843 854 855 858 859 860 861 862 + 863 864 865 866 867 868 869 885 886 898 899 902 903 904 905 906 907 908 + 914 915 916 917 918 920 921 922 923 924 925 926 927 928 929 940 941 942 + 943 944 945 946 947 948 949 967 970 973 978 980 981 982 983 984 985 986 + 987 988 989) + "Those exchanges which have moved from the 213 area code to the new 310.") + +(defun bbdb-convert-213-to-310 () + "Convert phone numbers in the BBDB which are in the 213 area code to the +newly-created 310 area code if appropriate." + (let ((records (bbdb-records)) + phones frobbed change-p) + (while records + (setq phones (bbdb-record-phones (car records)) + change-p nil) + (while phones + (if (and (= (bbdb-phone-area (car phones)) 213) + (memq (bbdb-phone-exchange (car phones)) bbdb-310-exchanges)) + (setq change-p (bbdb-phone-set-area (car phones) 310))) + (setq phones (cdr phones))) + (if change-p + (progn + (setq frobbed (cons (car records) frobbed)) + (bbdb-change-record (car records) nil))) + (setq records (cdr records))) + (bbdb-display-records frobbed))) diff --git a/xemacs-packages/etc/bbdb/bbdb-415-510.el b/xemacs-packages/etc/bbdb/bbdb-415-510.el new file mode 100644 index 00000000..28701511 --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-415-510.el @@ -0,0 +1,87 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; The San Francisco Bay Area, which was formerly area code 415, has been +;;; split into two area codes: 415 for the west side of the bay, and 510 +;;; for the east side. This code will map over your Insidious Big Brother +;;; Database and convert the area codes when approriate. It then displays +;;; the records which it has changed. + +(require 'bbdb) + +(defconst bbdb-415-exchanges + '(206 219 221 227 239 241 243 244 252 255 257 258 259 266 267 282 285 289 + 291 292 296 306 307 312 321 322 323 324 325 326 327 328 329 330 331 332 + 333 334 335 336 337 338 340 341 342 343 344 345 346 347 348 349 354 355 + 358 359 361 362 363 364 365 366 367 368 369 371 375 377 378 381 382 383 + 386 387 388 389 391 392 393 394 395 396 397 398 399 403 404 406 421 424 + 431 432 433 434 435 441 442 445 449 453 454 456 457 459 461 464 465 466 + 467 468 469 472 473 474 476 477 478 479 485 488 491 492 493 494 495 496 + 497 499 502 506 507 508 512 513 541 542 543 544 545 546 550 552 553 554 + 556 557 558 561 563 564 565 566 567 570 571 572 573 574 576 578 579 583 + 584 585 586 587 588 589 591 592 593 594 595 597 599 604 610 616 617 621 + 622 626 627 637 641 647 648 661 662 663 664 665 666 668 669 673 677 681 + 688 691 692 694 695 696 697 701 703 705 715 721 723 725 726 728 731 737 + 738 739 742 744 747 749 750 751 752 753 755 756 759 761 764 765 768 771 + 772 773 774 775 776 777 780 781 788 789 804 806 807 813 821 822 824 826 + 851 852 853 854 855 856 857 858 859 861 863 864 868 871 872 873 875 876 + 877 878 879 882 883 885 892 894 896 897 898 903 904 905 912 917 921 922 + 923 924 925 926 927 928 929 931 940 941 948 949 951 952 953 954 955 956 + 957 960 961 962 964 965 966 967 968 969 972 973 974 978 979 981 982 983 + 984 985 986 989 991 992 993 994 995 997 998) + "Those exchanges which are still in the 415 area code.") + +(defconst bbdb-510-exchanges + '(204 208 210 215 222 223 224 226 228 229 231 232 233 234 235 236 237 238 + 245 246 248 251 253 254 256 261 262 263 268 271 272 273 275 276 277 278 + 283 284 287 293 294 295 297 302 308 313 317 339 351 352 356 357 370 372 + 373 374 376 420 422 423 425 426 427 428 429 430 436 437 438 439 443 444 + 446 447 448 451 452 455 458 460 462 463 471 475 481 482 483 484 486 487 + 489 490 498 515 516 521 522 523 524 525 526 527 528 529 530 531 532 533 + 534 535 536 537 538 539 540 547 548 549 551 559 562 568 569 577 581 582 + 596 598 601 602 603 606 609 613 614 618 620 623 624 625 631 632 633 634 + 635 636 638 639 642 643 644 645 646 649 651 652 653 654 655 656 657 658 + 659 667 670 671 672 674 675 676 678 680 682 683 684 685 686 687 689 704 + 706 708 709 713 716 717 718 724 727 729 732 733 734 735 736 741 743 745 + 746 748 754 757 758 762 763 769 778 779 782 783 784 785 786 787 790 791 + 792 793 794 795 796 797 798 799 801 803 810 814 815 819 820 823 825 827 + 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 845 846 + 847 848 849 862 865 866 867 869 874 881 884 886 887 888 889 891 893 895 + 901 910 930 932 933 934 935 937 938 939 942 943 944 945 946 947 975 977 + 987) + "Those exchanges which have moved from the 415 area code to the new 510.") + + +(defsubst bbdb-convert-415-to-510-internal (phone) + (cond ((memq (bbdb-phone-exchange phone) bbdb-510-exchanges) + (if (= (bbdb-phone-area phone) 510) + nil + (bbdb-phone-set-area phone 510))) + ((memq (bbdb-phone-exchange phone) bbdb-415-exchanges) + (if (= (bbdb-phone-area phone) 415) + nil + (bbdb-phone-set-area phone 415))) + (t (error "Exchange %03d is not in the 415 or 510 area codes: %s" + (bbdb-phone-exchange phone) + (bbdb-phone-string phone))))) + + +(defun bbdb-convert-415-to-510 () + "Convert phone numbers in the BBDB which are in the 415 area code to the +newly-created 510 area code if appropriate." + (let ((records (bbdb-records)) + phones frobbed change-p) + (while records + (setq phones (bbdb-record-phones (car records)) + change-p nil) + (while phones + (if (memq (bbdb-phone-area (car phones)) '(415 510)) + (setq change-p + (or (bbdb-convert-415-to-510-internal (car phones)) + change-p))) + (setq phones (cdr phones))) + (if change-p + (progn + (setq frobbed (cons (car records) frobbed)) + (bbdb-change-record (car records) nil))) + (setq records (cdr records))) + (bbdb-display-records frobbed))) diff --git a/xemacs-packages/etc/bbdb/bbdb-areacode-split.pl b/xemacs-packages/etc/bbdb/bbdb-areacode-split.pl new file mode 100755 index 00000000..b77e65fb --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-areacode-split.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +# +# Looks for phone numbers in your .bbdb with a particular area code +# and one of a set of exchanges and changes the area code. The old +# and new area codes are specified on the command line, as is the +# location of a file that contains the exchanges that are being +# changed. (The format of that file is very loose. Every three digit +# sequence will be used.) +# +# Seth Golub +# 15 Aug 1997 + +sub Usage +{ + $0 =~ s@.*/@@; + die "Usage: \n $0 [bbdb]\n"; +} + +$old_area_code = shift || Usage(); +$new_area_code = shift || Usage(); +$exchange_list_file = shift || Usage(); + +$bbdb_file = $ENV{'BBDB'} || shift || $ENV{'HOME'} . '/.bbdb'; +$bbdb_dir = `dirname $bbdb_file`; chomp $bbdb_dir; +$tmp_file = "$bbdb_dir/bbdb.new-$$"; + +open( LIST, "<$exchange_list_file" ) + || die "Failed to open $exchange_list_file\n"; + +while () +{ + while ( /(\d\d\d)/g ) + { + push( @exchanges, $1 ); + } +} + +close( LIST ); + +$exchanges = join( '|', @exchanges ); + +open( BBDB_IN, "<$bbdb_file" ) || die "Failed to open $bbdb_file\n"; +open( BBDB_OUT, ">$tmp_file" ) || die "Failed to open $tmp_file\n"; + +while () +{ + next unless /^\[/; + s/(\[\".*?\") $old_area_code (($exchanges) \d+ \d+\])/$1 $new_area_code $2/og; +} continue { + print BBDB_OUT; +} + +close( BBDB_IN ); +close( BBDB_OUT ); + +unlink( "$bbdb_file.bak" ); +rename( $bbdb_file, "$bbdb_file.bak" ); +rename( $tmp_file, $bbdb_file ); + +print STDERR "Old bbdb moved to $bbdb_file.bak\n"; + +__END__ diff --git a/xemacs-packages/etc/bbdb/bbdb-cid.pl b/xemacs-packages/etc/bbdb/bbdb-cid.pl new file mode 100755 index 00000000..3bc4cdea --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-cid.pl @@ -0,0 +1,516 @@ +#!/usr/local/bin/perl5 -w +# +# Caller-ID-logger, by jwz (19-Jan-97) +# Modified: 24-Apr-97 +# +# Opens the modem and waits for it to print caller-ID data. When it does, +# it logs it to a file, parses it, and pops up a window using "xmessage". +# If the number is present in your .bbdb file, it shows the name (or company) +# associated with it. +# +# Todo: +# My caller ID service (in San Francisco) only ever sends numbers, not names, +# so I've never seen a "name" line come in; I assume that it would send both +# a name and a number, so it would be nice to present both (with error +# checking against BBDB) but the code as currently structured only handles +# one-line-per-call. It should realize that consecutive lines with the same +# timestamp are the same call. +# +# Modems other than ZyXELs have different caller-ID formats, and this doesn't +# deal with those. + +############################################################################## +# +# Some variables you might want to set... + + +# Set this to the device that your modem is attached to. +# +$modem_device = "/dev/ttyd1"; + +# This is your .bbdb file. (Set it to null if you don't want to do BBDB +# lookups at all, but why would you want to go and do a thing like that?) +# +$bbdb_file = "$ENV{HOME}/.bbdb"; + +# A shell command to use to cause emacs to pop up the BBDB buffer +# (bbdb-srv.pl is a good choice, so it defaults to the value of the +# shell environment variable $NS_MSG_DISPLAY_HOOK.) +# +$bbdb_cmd = $ENV{NS_MSG_DISPLAY_HOOK}; + +# If you want the $bbdb_cmd to be run on a different host, set it here. +# +$bbdb_host = "gimp"; + +# If you want each call to be logged to a file as well, name it here. +# +$logfile = "/usr/spool/fax/log/cid-log"; + +# For verbosity... +$debug = 0; + +# How to pop up a dialog box. +# +$xmessage_cmd = "xmessage"; +@xmessage_args = ("-display", ":0", + "-name", "Caller ID", + # roughly centered on my screen; YMMV. + "-geometry", "+400+400", + "-xrm", "*Font: -*-new cent*-bold-r-normal-*-240-*", + "-xrm", "*Foreground: black", + "-xrm", "*Background: lightgreen", + # no buttons on the window: dismiss it by clicking in it. + "-button", "", + "-xrm", "*form.Translations: #override : exit(0)", + "-xrm", "*Command.Font: -*-new cent*-bold-r-normal-*-120-*", + "-xrm", "*Command.horizDistance: 130" + ); + +# Uh, let's turn off the screensaver before popping up the window. +# +$pre_dialog_cmd = "xscreensaver-command -deactivate"; + + +# commands (and their expected responses) used to initialize the modem. +# +@modem_init = ( "AT", "OK", # ping + "ATZ", "OK", # reset + "ATE0", "OK", # don't echo commands + "ATM0", "OK", # turn off speaker + "ATN0", "OK", # turn off ringer + "ATS40.2=1", "OK", # turn on caller ID + ); + + +# for diagnostics: if the modem ever asynchronously prints something that +# doesn't match this, we issue a warning. +# +$expected_responses = "^CALLER NUMBER" . "|" . + "^REASON FOR NO CALLER " . "|" . + "^RING" . "|" . + "^TIME: [-0-9: ]+\$"; + + +############################################################################## +# +# Talking to the serial port... +# +# + +if ( $ debug ) { + use diagnostics; +} + + +sub open_modem { + use IPC::Open2; + + # Close the terminal streams before forking `cu', because otherwise + # it fucks around with the stty settings. + # + open(SAVEIN, "<&STDIN") || die("can't dup stdin"); + open(SAVEOUT, ">&STDOUT") || die("can't dup stdout"); + open(SAVEERR, ">&STDERR") || die("can't dup stderr"); + close(STDIN); + close(STDOUT); + close(STDERR); + + my $cu_pid = open2( \*MODEM_IN, \*MODEM_OUT, + "cu -l$modem_device -s2400 2>&1"); + + # Now that cu has been launched, we can restore them. + # + open(STDIN, "<&SAVEIN") || die("can't restore stdin"); + open(STDOUT, ">&SAVEOUT") || die("can't restore stdout"); + open(STDERR, ">&SAVEERR") || die("can't restore stderr"); + close(SAVEIN); + close(SAVEOUT); + close(SAVEERR); + + # The following doesn't seem to work and I don't know why... + # + # Set up a signal handler to try and kill off the cu process + # when we exit, instead of waiting ~30 seconds for it to notice + # that the pipe is gone... + # +# $SIG{INT} = sub { my $signame = shift; +# if ( $debug) { +# print STDERR "sending $signame to $cu_pid\n"; +# } +# print MODEM_OUT "\r\n~.\r\n"; +# close MODEM_OUT; +# close MODEM_IN; +# kill ($signame, $cu_pid); +# exit (1); +# }; + + $_ = ; + chop; + if ( !m/^Connected/ ) { + print STDERR "$0: cu printed `$_' instead of `Connected'\n"; + } +} + +sub read_line { + $_ = ; + $_ || die("got eof on modem"); + s/[\r\n]+$//; + if ( $_ eq "" ) { + $_ = ; + $_ || die("got eof on modem"); + s/[\r\n]+$//; + } + return $_; +} + +sub command { + my ( $command, $expected_response) = @_; + + if ( $debug ) { + print STDERR "sending: $command\n"; + } + + print MODEM_OUT "$command\r\n"; + my $line = read_line(); + + if ( $line eq $command ) { + if ( $debug ) { + print STDERR " got echo: reading next line too...\n"; + } + $line = read_line(); + } + + if ( $line ne $expected_response ) { + print STDERR " got: $line ; expected: $expected_response\n"; + } elsif ( $debug ) { + print STDERR " got: $line\n"; + } +} + +sub init_modem { + open_modem; + + my $len = $#modem_init + 1; + my $i; + for ($i = 0; $i < $len; $i += 2) { + command($modem_init[$i], $modem_init[$i+1]); + } +} + +sub handle_async_line { + local ( $_ ) = @_; + + if (!m/$expected_responses/) { + print STDERR "modem turd: $_\n"; + + } elsif (m/CALLER/) { + if ( $debug ) { + print STDERR "caller: $_\n"; + } + handle_cid_line($_); + + } elsif ( $debug ) { + if ( $_ eq '' ) { + print STDERR "ignored: blank line\n"; + } else { + print STDERR "ignored: $_\n"; + } + } +} + + +############################################################################## +# +# Parsing BBDB and CID data... +# + +sub find_bbdb_record { + my ( $area, $exchange, $suffix ) = @_; + + if ( ! $bbdb_file ) { + return undef; + } + + # strip off leading 0's, to match the way it's stored in .bbdb. + $area =~ s/^0+(.)/$1/; + $exchange =~ s/^0+(.)/$1/; + $suffix =~ s/^0+(.)/$1/; + + my $bbdb_rec = undef; + my $pat = "\\[\"[^\"]+\" $area $exchange $suffix (nil|[0-9]+)\\]"; + + open(BBDB, "<$bbdb_file") || die("error opening $bbdb_file: $!\n"); + + while () { + if ( m/$pat/ ) { + $bbdb_rec = $_; + last; + } + } + close(BBDB); + return $bbdb_rec; +} + + +# note: global (kludge!) +$pretty_number = 0; + +sub make_message_string { + my ( $number, $date, $fn, $ln, $co, $error ) = @_; + my $msg; + + my $line_prefix = " "; + my $line_suffix = " "; + + # First print the date (reformatted.) + # + $_ = $date; + my ( $dotw, $mon, $day, $hr, $min, $sec, $year ) = + m/^([^ ]+) +([^ ]+) +([^ ]+) +([^:]+):([^:]+):([^:]+) +([^ ]+) *$/; + $year =~ s/^..(..)/$1/; + $day =~ s/^0//; + $hr =~ s/^0//; + if ($hr < 12) { + $ampm = "am"; + } else { + $ampm = "pm"; + if ($hr > 12) { $hr -= 12 }; + } + $date = "$hr:$min$ampm, $day-$mon-$year ($dotw)"; + $msg = $line_prefix . $date . $line_suffix; + + # Next print the caller name, company, or error message. + # + if ( $error ) { + $msg .= "\n" . $line_prefix . $error . $line_suffix; + } elsif ( $co && !$fn && !$ln ) { + $msg .= "\n" . $line_prefix . $co . $line_suffix; + } elsif ( $fn || $ln ) { + $msg .= "\n" . $line_prefix . "$fn $ln" . $line_suffix; + } + + # Next print the phone number (formatted nicely.) + # + if ( $number ) { + my $area = 0; + my $exchange = 0; + my $suffix = 0; + $_ = $number; + ( $area, $exchange, $suffix ) = + m/^([0-9][0-9][0-9])([0-9][0-9][0-9])([0-9][0-9][0-9][0-9]+)/; + + # note: global (kludge!) + $pretty_number = "($area) $exchange-$suffix"; + $msg .= "\n" . $line_prefix . $pretty_number . $line_suffix; + } + + return $msg; +} + +use POSIX; +sub reaper { + $SIG{CHLD} = \&reaper; # loathe sysV + my $signame = shift; + if ( $debug >= 2 ) { + printf STDERR " (got SIG$signame...)\n"; + } + my $child; + while ( ( $child = waitpid(-1,WNOHANG) ), + $child > 0 ) { + if ( $debug >= 2 ) { + printf STDERR " (pid $child exited with $?)\n"; + } + } +} + +sub fork_and_exec { + my @cmd_list = @_; + + $SIG{CHLD} = \&reaper; + + if ( $debug >= 2 ) { + $_ = $cmd_list[0]; + s/ .*//; + print STDERR "forking for " . $_ . " at " . (localtime) . ".\n"; + } + + my $pid; + if ($pid = fork()) { + # parent + } elsif (!defined $pid) { + print STDERR "$0: fork failed: $!\n"; + } else { + # child + + if ( $debug ) { + $_ = $cmd_list[0]; + s/ .*//; + print STDERR "exec'ing " . $_ . " at " . (localtime) . + " in pid $$.\n"; + } + close(STDIN); + close(STDOUT); + close(STDERR); + exec @cmd_list; + } +} + + +sub fork_and_exec_for_bbdb { + my @cmd_list = @_; + my $number = shift @cmd_list; + + $SIG{CHLD} = \&reaper; + + if ( $debug >= 2 ) { + $_ = $cmd_list[0]; + s/ .*//; + print STDERR "forking for " . $_ . " at " . (localtime) . ".\n"; + } + + my $pid; + if ($pid = fork()) { + # parent + } elsif (!defined $pid) { + print STDERR "$0: fork failed: $!\n"; + exit (1); + } else { + # child + + if ( $debug ) { + $_ = $cmd_list[0]; + s/ .*//; + print STDERR "exec'ing " . $_ . " at " . (localtime) . + " in pid $$.\n"; + } + if ( system @cmd_list ) { + my $cmd = "gnudoit -q '(bbdb-srv-add-phone \"$pretty_number\")'"; + if ( $bbdb_host ) { + $cmd =~ s/([()\"])/\\$1/g; + $cmd = "rsh $bbdb_host $cmd"; + } + exec $cmd; + } + exit (0); + } +} + + +sub pop_up_dialog { + my ( $msg, $buttonp, $number ) = @_; + + fork_and_exec $pre_dialog_cmd; + + if ( ! $buttonp ) { + fork_and_exec $xmessage_cmd, @xmessage_args, "\n$msg\n\n"; + } else { + my @args = ( @xmessage_args, "-button", "Add To BBDB" ); + fork_and_exec_for_bbdb $number, $xmessage_cmd, @args, "\n$msg\n\n"; + } +} + +sub pop_up_bbdb_buffer { + my ( $caller ) = @_; + if ( $bbdb_cmd ) { + my $cmd = $bbdb_cmd; + if ( $bbdb_host ) { + $cmd = "rsh $bbdb_host $cmd"; + } + $caller =~ s/\\/\\\\/g; + $caller =~ s/\"/\\\\\"/g; + `echo "Path:\nFrom: \\\"$caller\\\" <>" | $cmd >&- 2>&- &`; + } +} + + +sub handle_cid_line { + my($line) = @_; + + my $date = localtime; + + # Log the call... + # + if ( $logfile ) { + if (open(LOG, ">>$logfile")) { + print LOG "$date\t$line\r\n"; + close LOG; + } else { + print STDERR "error opening $logfile: $!\n"; + } + } + + # Pull the phone number out of the message... + # + my $number = ""; + my $error = ""; + + $_ = $line; + if ( m/^CALLER NUMBER/ ) { + ( $number ) = m/^[^:]+: *(.*) *$/; + } else { + $error = $line; + } + + my $caller = undef; + + my $fn = undef; + my $ln = undef; + my $co = undef; + my $buttonp = 0; + + if ( !$number || $number eq "" ) { + $error =~ tr#A-Z#a-z#; + $error =~ s/^REASON FOR NO CALLER (NUMBER|NAME)/Caller unknown/i; + + } else { + $_ = $number; + + my $area = 0; + my $exchange = 0; + my $suffix = 0; + ( $area, $exchange, $suffix ) = + m/^([0-9][0-9][0-9])([0-9][0-9][0-9])([0-9][0-9][0-9][0-9]+)/; + + my $bbdb_rec = find_bbdb_record($area, $exchange, $suffix); + + if ( $bbdb_rec ) { + my $junk = 0; + $_ = $bbdb_rec; + # This will lose if names or aliases have double-quotes in them. + # No doubt there's some hairier regexp magic that handles that... + ( $fn, $ln ) = m/^[\[]\"([^\"]*)\" *\"([^\"]*)\"/; + ( $junk, $junk, $junk, $co ) = + m/^[[](nil|\"[^\"]*\") *(nil|\"[^\"]*\") (nil|[(][^)]*[)]) \"([^\"]*)\"/; + + if ( $fn || $ln ) { + $caller = "$fn $ln"; + } + } else { + $buttonp = 1; + } + } + + my $msg = make_message_string($number, $date, $fn, $ln, $co, $error); + pop_up_dialog($msg, $buttonp, $pretty_number); + + if ( $caller ) { + pop_up_bbdb_buffer($caller); + } +} + + +############################################################################## +# +# hey ho. let's go. +# +sub main { + init_modem(); + while (1) { + handle_async_line(read_line()); + } + exit (1); +} + +main(); + diff --git a/xemacs-packages/etc/bbdb/bbdb-srv.pl b/xemacs-packages/etc/bbdb/bbdb-srv.pl new file mode 100755 index 00000000..019adf6f --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-srv.pl @@ -0,0 +1,45 @@ +#!/usr/local/bin/perl + +# This script reads a block of message headers on stdin, and converts them +# to an emacs-lisp string (quoting all dangerous characters) and then +# uses the `gnudoit' program to cause a running Emacs process to invoke +# the `bbdb-srv' function with that string. +# +# This has the effect of causing the running Emacs to display the BBDB +# record corresponding to these headers. +# +# See the Emacs side of things in bbdb-srv.el for more info. +# +# A trivial application of this is the shell command: +# +# echo 'From: Jamie Zawinski ' | bbdb-srv.perl +# +# which will cause the corresponding record to be displayed. +# A more interesting application of this is: +# +# setenv NS_MSG_DISPLAY_HOOK bbdb-srv.perl +# +# which will hook BBDB up to Mozilla (Unix Netscape Mail and Netscape News +# versions 3.0b2 and later only.) +# +# -- Jamie Zawinski , 25-apr-96 + +# spawn in the background and return to the caller immediately. +if (fork == 0) { exit 0; } + +$str="(bbdb-srv \""; +while(<>) +{ + # quote most shell metacharacters with backslash. + s/([\\"`$#^!])/\\\1/g; + # but quote ' as \047 + s/'/\\047/g; + # and just for kicks, turn newlines into \n +# s/\n/\\n/g; + + $str = $str.$_; +} +$str=$str."\")"; + +exec "gnudoit", "-q", $str; +exit 0; diff --git a/xemacs-packages/etc/bbdb/bbdb-to-netscape.el b/xemacs-packages/etc/bbdb/bbdb-to-netscape.el new file mode 100644 index 00000000..cf7d5a4b --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-to-netscape.el @@ -0,0 +1,213 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file is the part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992, 1993, 1995 Jamie Zawinski . +;;; Converting a BBDB database to a Netscape Address Book. +;;; last change21-feb-97. + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; This file attempts to convert a BBDB database to a Netscape Address Book +;;; file. It doesn't work very well. If you fix it, let me know. -- jwz + +(require 'bbdb) + +(defun bbdb-mozilla-insert-url (string) + (let ((p (point)) + c) + (insert string) + (goto-char (prog1 p (setq p (point)))) + (while (progn + (skip-chars-forward "-a-zA-Z0-9.@/_\r\n" p) + (< (point) p)) + (setq c (following-char)) + (delete-char 1) + (insert (format "%%%02X" c)) + (setq p (+ 2 p))) + (goto-char p))) + +(defun bbdb-mozilla-insert-html (string) + (let ((p (point)) + c) + (insert string) + (goto-char (prog1 p (setq p (point)))) + (while (progn + (skip-chars-forward "^&<>" p) + (< (point) p)) + (setq c (following-char)) + (delete-char 1) + (cond ((= c ?&) (insert "&") (setq p (+ p 4))) + ((= c ?<) (insert "<") (setq p (+ p 3))) + (t (insert ">") (setq p (+ p 3))))) + (goto-char p))) + +(defun bbdb-mozilla-emit-record (record aliases) + (let (addr) + (cond ((setq addr (car (bbdb-record-net record))) + (insert "
")) + (let ((name (or (bbdb-record-name record) + (bbdb-record-company record) + ""))) + (bbdb-mozilla-insert-html name)) + (insert "\n") + (let ((notes nil)) + (cond (notes + ))) + t) + (t nil)))) + +(defun bbdb-to-netscape () + (let* ((target (cons bbdb-define-all-aliases-field + "^[a-z, ]+$")) + (records1 (bbdb-search (bbdb-records) + nil ; name + nil ; company + nil ;"netscape\\.com" ; net + target ; notes + )) + (records records1) + result record aliases match + (lists nil) + (single-aliases nil) + (count 0) + ) + (message "%d" (length records1)) + (while records + (setq record (car records)) + (setq aliases (bbdb-record-getprop record bbdb-define-all-aliases-field)) + (setq aliases (and aliases (bbdb-split aliases ","))) + (while aliases + (if (setq match (assoc (car aliases) result)) + (nconc match (cons record nil)) + (setq result (cons (list (car aliases) record) result))) + (setq aliases (cdr aliases))) + (setq records (cdr records))) + (while result + (let ((alias (downcase (car (car result)))) + (expansion (cdr (car result)))) + (cond + ((cdr expansion) + (setq lists (cons (cons alias expansion) lists))) + (expansion + (setq single-aliases (cons (cons (car expansion) alias) + single-aliases)))) + (setq result (cdr result)))) + +; (setq records (bbdb-records)) + (setq records records1) + (set-buffer (get-buffer-create "*netscape-address-book*")) + (erase-buffer) + (insert "\n" + "\n" + "" (user-full-name) "'s Address book\n" + "

" (user-full-name) "'s Address book

\n" + "\n" + "

\n") + (while records + (setq record (car records)) + (insert "

") + (insert (or (bbdb-record-name record) + net + (bbdb-record-company record) + ""))) + + (insert "\n") + (let ((phones (bbdb-record-phones record)) + (addrs (bbdb-record-addresses record)) + (aka (bbdb-record-aka record)) + phone + ) + + (insert "
") + (setq match nil) + (while phones + (setq phone (car phones)) + (setq match t) + (insert (format " %14s: " (bbdb-phone-location phone))) + (insert (bbdb-phone-string phone) "\n
") + (setq phones (cdr phones))) + (let (addr c s) + (while addrs + (setq addr (car addrs)) + (setq match t) + (insert (format " %14s: " (bbdb-address-location addr))) + (if (= 0 (length (setq s (bbdb-address-street1 addr)))) nil + (indent-to 17) (insert s "\n
")) + (if (= 0 (length (setq s (bbdb-address-street2 addr)))) nil + (indent-to 17) (insert s "\n
")) + (if (= 0 (length (setq s (bbdb-address-street3 addr)))) nil + (indent-to 17) (insert s "\n
")) + (indent-to 17) + (insert (setq c (bbdb-address-city addr))) + (setq s (bbdb-address-state addr)) + (if (and (> (length c) 0) (> (length s) 0)) (insert ", ")) + (insert s " ") + (insert (bbdb-address-zip-string addr) "\n
") + (setq addrs (cdr addrs)))) + (cond (aka + (setq match t) + (insert (format " %14s: %s\n
" "AKA" + (mapconcat (function identity) aka ", "))))) + (let ((notes (bbdb-record-raw-notes record))) + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + (while notes + (if (memq (car (car notes)) + '(mail-alias password bbdb mail-name face mark-char aka)) + nil + (setq match t) + (insert (format " %14s: " (car (car notes)))) + (let ((p (point))) + (insert (cdr (car notes))) + (save-excursion + (save-restriction + (narrow-to-region p (1- (point))) + (goto-char (1+ p)) + (while (search-forward "\n" nil t) + (forward-char -1) + (insert "
") + (forward-char 1) + (insert (make-string 17 ?\ ))))) + (insert "\n"))) + (setq notes (cdr notes))))) + + (or match (delete-char -4)) + + (setq records (cdr records)) + ) + (insert "

\n") + )) diff --git a/xemacs-packages/etc/bbdb/bbdb-unlazy-lock.pl b/xemacs-packages/etc/bbdb/bbdb-unlazy-lock.pl new file mode 100755 index 00000000..a92dcd00 --- /dev/null +++ b/xemacs-packages/etc/bbdb/bbdb-unlazy-lock.pl @@ -0,0 +1,19 @@ +#!/usr/local/bin/perl +# +# Author: Christopher Kline +# +# bbdb-unlazy-lock.pl,v 1.1 1997/10/06 00:56:14 simmonmt Exp +# +# bbdb-unlazy-lock.pl,v +# Revision 1.1 1997/10/06 00:56:14 simmonmt +# Initial revision +# +# +# Lazy-lock-mode has (had) a nasty habit of munging .bbdb files if you visited them +# with it on. This script removes the lazy-lock mung +# + +while( ) { + s/#\(("[^"]*")( \d+ \d+ (nil)*(\(lazy-lock t\))*)*\)/$1/gi; + print; +} diff --git a/xemacs-packages/etc/bbdb/tex/bbdb-cols.tex b/xemacs-packages/etc/bbdb/tex/bbdb-cols.tex new file mode 100644 index 00000000..4102d0f7 --- /dev/null +++ b/xemacs-packages/etc/bbdb/tex/bbdb-cols.tex @@ -0,0 +1,234 @@ +%%% bbdb-cols.tex - multiple columns per page, multiple pages per sheet. + +%%% Authors: Luigi Semenzato +%%% Boris Goldowsky +%%% Copyright (C) 1993 Boris Goldowsky +%%% Version: 3.92; 5Jan95 + +%%% Commentary: +%%% +%%% Put \input bbdb-cols.tex +%%% at the beginning of your TeX file. +%%% Then \twocol, \threecol, or \fourcol for multi-column output +%%% or \gridformat (4x3 grid of small credit-card-sized pages) +%%% or \quadformat{xsize}{ysize} for four 2-column pages per sheet. +%%% In any case you will need to put \endcol at the end of the +%%% document, before \bye. + +%%% For instructions on using this format file with BBDB, see bbdb-print.el +%%% which should have come bundled with this file. The complete bbdb-print +%%% package is also available via anonymous ftp at: +%%% /cs.rochester.edu:/pub/u/boris/bbdb-print.tar.gz + +%%% This file is part of the bbdb-print extensions to the Insidious +%%% Big Brother Database, which is for use with GNU Emacs. +%%% +%%% This program 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 1, or +%%% (at your option) any later version. +%%% +%%% This program 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + +\newdimen\colshsize \colshsize=\hsize +\newdimen\columngutter \columngutter=.2in % space between columns + +\newbox\columnA \newbox\columnB \newbox\columnC + +\newdimen\FULLHSIZE +\newdimen\FULLVSIZE +\newbox\quadrantbox +\newbox\firstquadrant \newbox\secondquadrant +\newbox\thirdquadrant \newbox\fourthquadrant +\newbox\row \newbox\page + +\def\columnbox{\leftline{\pagebody}} + +\def\colsline{\hbox to \colshsize} + +\newcount\NROW \NROW=3 % for grid format. are these really variables +\newcount\NCOL \NCOL=4 % that can be changed? should they be set + % from lisp? I'm not sure. +\newcount\rowindex \newcount\colindex + +\def\onecol % for consistency---or maybe one could use it for switching back. +{ + \output={\shipout\vbox{\makeheadline\colsline{\columnbox}\makefootline} + \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + \def\endcol{} +}% end onecol + +\def\twocol +{ + \advance\hsize by -\columngutter + \divide\hsize 2 + \let\column=A + \output={\if A\column + \global\setbox\columnA=\columnbox \global\let\column=B + \else + \shipout\vbox{\makeheadline + \colsline{\box\columnA\hfil\columnbox} + \makefootline} + \advancepageno \global\let\column=A + \fi + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + + \def\endcol + { + \vfill\supereject\if A\column \else\null\vfill\eject\fi + } + +} % end twocol + +\def\threecol +{ + \advance\hsize -\columngutter + \advance\hsize -\columngutter + \divide\hsize 3 + \let\column=A + \output={\if A\column + \global\setbox\columnA=\columnbox \global\let\column=B + \else \if B\column + \global\setbox\columnB=\columnbox \global\let\column=C + \else + \shipout\vbox{\makeheadline + \colsline{\box\columnA\hfil\box\columnB + \hfil\columnbox} + \makefootline} + \advancepageno \global\let\column=A + \fi\fi + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + + \def\endcol + { + \if A\column + \null\vfill\eject\null\vfill\eject + \else\if B\column + \null\vfill\eject + \fi\fi + \vfill\supereject + } + +} % end threecol + +\def\fourcol +{ + \advance\hsize -3\columngutter + \divide\hsize 4 + \let\column=A + \output={\if A\column + \global\setbox\columnA=\columnbox \global\let\column=B + \else \if B\column + \global\setbox\columnB=\columnbox \global\let\column=C + \else \if C\column + \global\setbox\columnC=\columnbox \global\let\column=D + \else + \shipout\vbox + { \makeheadline + \colsline{\box\columnA\hfil\box\columnB\hfil + \box\columnC\hfil\columnbox} + \makefootline} + \advancepageno\global\let\column=A + \fi\fi\fi + \ifnum\outputpenalty>-20000 \else\dosupereject\fi + } + + \def\endcol + { + \vfill\supereject + \if A\column \else\null\vfill\eject\fi + \if B\column \else\null\vfill\eject\fi + \if C\column \else\null\vfill\eject\fi + } + +} % end fourcol + +\def\quadformat#1#2 +{ + \FULLHSIZE=\hsize + \FULLVSIZE=\vsize + + \colshsize=#1 + \vsize=#2 + + \hsize=\colshsize \advance\hsize by -.15in \divide\hsize 2 + + \let\lr=L + \let\quadrant=A + \output={\if L\lr + \global\setbox\columnA=\columnbox \global\let\lr=R + \else + \global\setbox\quadrantbox=\vbox{\colsline + {\box\columnA\hfil\columnbox}} \global\let\lr=L + \quadrantformat + \fi + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + + \def\quadrantformat + {\if A\quadrant + \global\setbox\firstquadrant=\box\quadrantbox + \global\let\quadrant=B + \else \if B\quadrant + \global\setbox\secondquadrant=\box\quadrantbox + \global\let\quadrant=C + \else \if C\quadrant + \global\setbox\thirdquadrant=\box\quadrantbox + \global\let\quadrant=D + \else + {\shipout + \vbox to \FULLVSIZE + {\FULLLINE{\box\firstquadrant\hfil\box\secondquadrant} + \vfill + \FULLLINE{\box\thirdquadrant\hfil\box\quadrantbox}}} + \global\let\quadrant=A + \advancepageno + \fi\fi\fi} + + \def\FULLLINE{\hbox to \FULLHSIZE} + + \def\endcol{\supereject\if R\lr \null\vfill\eject\fi} +} % end of quadformat + +\def\grid +{ + \def\rowspace{\vbox to 0.2in{}} + \def\colspace{\hbox to 0.2in{}} + + \hsize=1.5in + \vsize=2.9in + + \rowindex=0 \colindex=0 + + \setbox\row=\null \setbox\page=\null + + \output={\global\advance\colindex by 1 + \ifnum\colindex>\NCOL + \global\colindex=1 + \global\setbox\page=\vbox{\box\page\rowspace\box\row} + \global\setbox\row=\null + \global\advance\rowindex by 1 + \ifnum\rowindex=\NROW + \global\rowindex=1 + \shipout\box\page + \global\setbox\page=\null + \advancepageno + \fi + \fi + \global\setbox\row=\hbox{\box\row\colspace\columnbox}} + + \def\columnbox{\leftline{\pagebody}} + + \def\endcol{\vfill\supereject + \ifnum\colindex=1\null\vfill\eject\fi} +} % end of grid. + +%%% bbdb-cols.tex ends here. + diff --git a/xemacs-packages/etc/bbdb/tex/bbdb-print-brief.tex b/xemacs-packages/etc/bbdb/tex/bbdb-print-brief.tex new file mode 100644 index 00000000..f1162708 --- /dev/null +++ b/xemacs-packages/etc/bbdb/tex/bbdb-print-brief.tex @@ -0,0 +1,159 @@ +%%% bbdb-print-brief.tex - for formatting address lists, one line per entry. + +%%% Authors: Luigi Semenzato +%%% Boris Goldowsky +%%% Copyright (C) 1993 Boris Goldowsky +%%% Version: 3.91; 19Dec94 + +%%% For instructions on using this format file with BBDB, see bbdb-print.el +%%% which should have come bundled with this file; or write to +%%% boris@cs.rochester.edu. + +%%% This file is part of the bbdb-print extensions to the Insidious +%%% Big Brother Database, which is for use with GNU Emacs. +%%% +%%% The Insidious Big Brother Database 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 1, or (at your +%%% option) any later version. +%%% +%%% BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +%%% The address-list file should look something like this: + +%%% \input file % this format file's filename +%%% \setsize{6} % point size of type to use +%%% % or \setpssize{6} to use PostScript fonts. (optional) +%%% \setseparator{3} % which style of separators, 0-7 +%%% +%%% \separator{A} % include a separator here +%%% +%%% \beginrecord % and start a record +%%% \name{A. Name} +%%% \phone{location: (xxx) xxx-xxxx} +%%% \address{1234 Main Street\\ +%%% Anytown, XX 00000\\} +%%% \note{note name}{note text} +%%% \notes{blah blah} +%%% \endrecord +%%% +%%% \endaddresses % done +%%% \bye + +\nopagenumbers +\raggedright +\tolerance=10000 +\hbadness=10000 +\parskip 0pt +\parindent=0pt % was 10pt + +%%% +%%% Fonts +%%% + +\def\setsize#1{ + \font\rm=ecrm#1 + \font\bf=ecbx#1 + \font\it=\ifnum #1=6 ecti7 \else ecti#1 \fi + \font\tt=ectt#1 + \font\bigbf=ecbx#1 scaled \magstep3 + \rm + \baselineskip=#1pt + \ifnum #1>9 \advance\baselineskip by 1pt \fi +} + +\def\setpssize#1{ + \font\rm=ptmr at #1pt + \font\bf=ptmb at #1pt + \font\it=ptmri at #1pt + \font\tt=pcrr at #1pt + {\dimen0=#1pt\global\font\bigbf=ptmb at 1.8\dimen0} + \rm + \baselineskip=#1pt +} + +%%% +%%% Define separator types +%%% + +\def\setseparator#1{ + \ifnum #1=1 + \def\sep##1{\line{\hrulefill}\smallskip\mark{##1}} + \else \ifnum #1=2 + \def\sep##1{\hbox{\vrule\hskip -0.4pt\vbox{\hrule\smallskip + \centerline{\bf{##1}}\smallskip\hrule}\hskip -0.4pt\vrule + \mark{##1}}} + \else \ifnum #1=3 + \def\sep##1{\hbox{\vrule\hskip -0.4pt\vbox{\hrule\smallskip + \centerline{\bigbf{##1}}\smallskip\hrule}\hskip -0.4pt\vrule} + \medskip\mark{##1}} + \else \ifnum #1=4 + \def\sep##1{\smallskip\centerline{\bigbf{##1}}\medskip\mark{##1}} + \else \ifnum #1=5 + \def\sep##1{\hrule\smallskip + \centerline{\bigbf{##1}}\smallskip\hrule\medskip\mark{##1}} + \else \ifnum #1=6 + \def\cute{$\sya\syb\syc\syd$} + \def\revcute{$\syd\syc\syb\sya$} + \let\sya=\heartsuit\let\syb=\spadesuit + \let\syc\diamondsuit\let\syd=\clubsuit + \def\cycle{\let\tmp=\sya\let\sya=\syb + \let\syb=\syc\let\syc=\syd\let\syd=\tmp} + \def\sep##1{\smallskip + \hbox to \hsize{\hfil\cute\hfil\bigbf{##1}\hfil\revcute\hfil} + \cycle\medskip\mark{##1}} + \else \ifnum #1=7 + \def\cute{$\sya\syb\syc\syd$} + \def\revcute{$\syd\syc\syb\sya$} + \let\sya=\heartsuit\let\syb=\spadesuit + \let\syc=\diamondsuit\let\syd=\clubsuit + \def\cycle{\let\tmp=\sya\let\sya=\syb\let\syb=\syc\let\syc=\syd + \let\syd=\tmp} + \def\sep##1{\hbox{\vrule\vbox{\hrule\smallskip + \hbox to \hsize{\hfil\cute\hfil\bigbf{##1}\hfil\revcute\hfil} + \smallskip\hrule}\vrule}\medskip\cycle\mark{##1}} + \else + \def\sep##1{\mark{##1}} + \fi\fi\fi\fi\fi\fi\fi + \def\separator##1{\noalign{\sep##1}} +} % end setseparator + +%%% +%%% Macros for formatting the entries. +%%% + +\def\\{} + +\def\firstline#1#2{% the name and (maybe) the first phone number. + {\bf #1}\hfil&\hfil#2&\hskip0pt} + +\def\name#1{\firstline{#1}{}} % for backwards compatibility + +\def\phone#1{\hfil#1&\hskip0pt} + +\def\address#1{#1\hfil&\hskip0pt} + +\def\comp#1{\hskip0pt} +\def\email#1{\hskip0pt} +\def\note#1#2{\hskip0pt} +\def\notes#1{\hskip0pt} + +\def\beginrecord{\relax} +\def\endrecord{\cr} + +\def\beginaddresses{\halign\bgroup&##\quad\cr} +\def\endaddresses{\egroup} + +\def\today{\number\day\space + \ifcase\month\or Jan\or Feb\or Mar\or Apr \or May\or June\or + Jul\or Aug\or Sept\or Oct\or Nov\or Dec\fi + \space\number\year} + +%%% bbdb-print-brief.tex ends here. diff --git a/xemacs-packages/etc/bbdb/tex/bbdb-print.tex b/xemacs-packages/etc/bbdb/tex/bbdb-print.tex new file mode 100644 index 00000000..9b60e4b8 --- /dev/null +++ b/xemacs-packages/etc/bbdb/tex/bbdb-print.tex @@ -0,0 +1,171 @@ +%%% bbdb-print.tex - for formatting address lists. + +%%% Authors: Luigi Semenzato +%%% Boris Goldowsky +%%% Copyright (C) 1993 Boris Goldowsky +%%% Version: 3.92; 5Jan95 + +%%% For instructions on using this format file with BBDB, see bbdb-print.el +%%% which should have come bundled with this file. The complete bbdb-print +%%% package is also available via anonymous ftp at: +%%% /cs.rochester.edu:/pub/u/boris/bbdb-print.tar.gz + +%%% This file is part of the bbdb-print extensions to the Insidious +%%% Big Brother Database, which is for use with GNU Emacs. +%%% +%%% This program 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 1, or +%%% (at your option) any later version. +%%% +%%% This program 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +%%% The address-list file should look something like this: + +%%% \input file % this format file's filename +%%% \setsize{6} % point size of type to use +%%% % or \setpssize{6} to use PostScript fonts. (optional) +%%% \setseparator{3} % which style of separators, 0-7 +%%% +%%% \separator{A} % include a separator here +%%% +%%% \beginrecord % and start a record +%%% \name{A. Name} +%%% \phone{location: (xxx) xxx-xxxx} +%%% \address{1234 Main Street\\ +%%% Anytown, XX 00000\\} +%%% \note{note name}{note text} +%%% \notes{blah blah} +%%% \endrecord +%%% +%%% \endaddresses % done +%%% \bye + +\raggedright +\tolerance=10000 +\hbadness=10000 +\parskip 0pt +\parindent=0pt +\footline{\hfil} + +%%% +%%% Fonts +%%% + +\def\setsize#1{ + \font\rm=ecrm#1 + \font\bf=ecbx#1 + \font\it=\ifnum #1=6 ecti7 \else ecti#1 \fi + \font\tt=ectt#1 + \font\bigbf=ecbx#1 scaled \magstep3 + \rm + \baselineskip=#1pt + \ifnum #1>9 \advance\baselineskip by 1pt \fi +} + +\def\setpssize#1{ + \font\rm=ptmr at #1pt + \font\bf=ptmb at #1pt + \font\it=ptmri at #1pt + \font\tt=pcrr at #1pt + {\dimen0=#1pt\global\font\bigbf=ptmb at 1.8\dimen0} + \rm + \baselineskip=#1pt +} + +%%% +%%% Define separator types +%%% + +\def\setseparator#1{ + \ifnum #1=1 + \def\separator##1{\hrule\smallskip\mark{##1}} + \else \ifnum #1=2 + \def\separator##1{\hbox{\vrule\hskip -0.4pt\vbox{\hrule\smallskip + \centerline{\bf{##1}}\smallskip\hrule}\hskip -0.4pt\vrule + \mark{##1}}} + \else \ifnum #1=3 + \def\separator##1{\hbox{\vrule\hskip -0.4pt\vbox{\hrule\smallskip + \centerline{\bigbf{##1}}\smallskip\hrule}\hskip -0.4pt\vrule} + \medskip\mark{##1}} + \else \ifnum #1=4 + \def\separator##1{\smallskip\centerline{\bigbf{##1}}\medskip\mark{##1}} + \else \ifnum #1=5 + \def\separator##1{\hrule\smallskip + \centerline{\bigbf{##1}}\smallskip\hrule\medskip\mark{##1}} + \else \ifnum #1=6 + \def\cute{$\sya\syb\syc\syd$} + \def\revcute{$\syd\syc\syb\sya$} + \let\sya=\heartsuit\let\syb=\spadesuit + \let\syc\diamondsuit\let\syd=\clubsuit + \def\cycle{\let\tmp=\sya\let\sya=\syb + \let\syb=\syc\let\syc=\syd\let\syd=\tmp} + \def\separator##1{\smallskip + \hbox to \hsize{\hfil\cute\hfil\bigbf{##1}\hfil\revcute\hfil} + \cycle\medskip\mark{##1}} + \else \ifnum #1=7 + \def\cute{$\sya\syb\syc\syd$} + \def\revcute{$\syd\syc\syb\sya$} + \let\sya=\heartsuit\let\syb=\spadesuit + \let\syc=\diamondsuit\let\syd=\clubsuit + \def\cycle{\let\tmp=\sya\let\sya=\syb\let\syb=\syc\let\syc=\syd + \let\syd=\tmp} + \def\separator##1{\hbox{\vrule\vbox{\hrule\smallskip + \hbox to \hsize{\hfil\cute\hfil\bigbf{##1}\hfil\revcute\hfil} + \smallskip\hrule}\vrule}\medskip\cycle\mark{##1}} + \else + \def\separator##1{\mark{##1}} + \fi\fi\fi\fi\fi\fi\fi +} % end setseparator + +%%% +%%% Macros for formatting the entries. +%%% + +\def\beginaddresses{} + +\def\endaddresses{ + \bigskip\hrule\smallskip + \noindent {\bf Printed \today}\vfill\endcol} + +\def\beginrecord{\bigbreak} + +\def\endrecord{\bigbreak} + +\def\\{\par} + +\def\dots{\leaders\hbox to 0.6em{\hss.\hss}} + +\def\firstline#1#2{% the name and (maybe) the first phone number. + \hyphenpenalty=10000\rightskip=0pt plus 1fil + \noindent{\bf #1}\dotfill\penalty-1\hbox{}\dotfill{#2}\\ +} + +\def\name#1{\firstline{#1}{}} % for backwards compatibility + +\def\comp#1{#1\\} + +\def\phone#1{\hfill#1\\} + +\def\email#1{\smallbreak{\tt#1}\\} + +\def\address#1{\smallbreak#1\smallbreak} + +\def\note#1#2{{\smallbreak\leftskip=2em\parindent=-1em + \noindent\hskip-\leftskip{\it#1: } #2\\ }} + +\def\notes#1{\smallbreak{\it(#1)}\\ } + +\def\today{\number\day\space + \ifcase\month\or Jan\or Feb\or Mar\or Apr \or May\or June\or + Jul\or Aug\or Sept\or Oct\or Nov\or Dec\fi + \space\number\year} + +%%% bbdb-print.tex ends here. diff --git a/xemacs-packages/etc/ediff/ediff-A-up.xbm b/xemacs-packages/etc/ediff/ediff-A-up.xbm new file mode 100644 index 00000000..338d6a49 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-A-up.xbm @@ -0,0 +1,6 @@ +#define ediff-A-up_width 15 +#define ediff-A-up_height 15 +static char ediff-A-up_bits[] = { + 0x00,0x80,0x00,0x80,0x00,0x80,0xc0,0x81,0xe0,0x83,0x60,0x83,0x70,0x87,0x30, + 0x86,0x38,0x8e,0xf8,0x8f,0x18,0x8c,0x18,0x8c,0x00,0x80,0x00,0x80,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-A-up.xpm b/xemacs-packages/etc/ediff/ediff-A-up.xpm new file mode 100644 index 00000000..e5fde45c --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-A-up.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *ediff_A[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 2 1", +/* colors */ +". c blue", +"# c Gray75 s backgroundToolBarColor", +/* pixels */ +"###############", +"###############", +"###############", +"######...######", +"#####.....#####", +"#####..#..#####", +"####...#...####", +"####..###..####", +"###...###...###", +"###.........###", +"###..#####..###", +"###..#####..###", +"###############", +"###############", +"###############", +}; diff --git a/xemacs-packages/etc/ediff/ediff-A-xx.xpm b/xemacs-packages/etc/ediff/ediff-A-xx.xpm new file mode 100644 index 00000000..50c6cfa1 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-A-xx.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *ediff_A[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 2 1", +/* colors */ +". c gray60", +"# c Gray75 s backgroundToolBarColor", +/* pixels */ +"###############", +"###############", +"###############", +"######...######", +"#####.....#####", +"#####..#..#####", +"####...#...####", +"####..###..####", +"###...###...###", +"###.........###", +"###..#####..###", +"###..#####..###", +"###############", +"###############", +"###############", +}; diff --git a/xemacs-packages/etc/ediff/ediff-B-up.xbm b/xemacs-packages/etc/ediff/ediff-B-up.xbm new file mode 100644 index 00000000..bcb82eb3 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-B-up.xbm @@ -0,0 +1,6 @@ +#define ediff-B-up_width 15 +#define ediff-B-up_height 15 +static char ediff-B-up_bits[] = { + 0x00,0x80,0x00,0x80,0xf8,0x81,0xf8,0x83,0x38,0x87,0x38,0x86,0xf8,0x83,0xf8, + 0x87,0x38,0x8e,0x38,0x8c,0x38,0x8e,0xf8,0x87,0xf8,0x83,0x00,0x80,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-B-up.xpm b/xemacs-packages/etc/ediff/ediff-B-up.xpm new file mode 100644 index 00000000..c9c4c5a9 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-B-up.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *ediff-B-up[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 2 1", +/* colors */ +". c blue", +"# c Gray75 s backgroundToolBarColor", +/* pixels */ +"###############", +"###############", +"###......######", +"###.......#####", +"###...##...####", +"###...###..####", +"###.......#####", +"###........####", +"###...###...###", +"###...####..###", +"###...###...###", +"###........####", +"###.......#####", +"###############", +"###############", +"###############" +}; diff --git a/xemacs-packages/etc/ediff/ediff-B-xx.xpm b/xemacs-packages/etc/ediff/ediff-B-xx.xpm new file mode 100644 index 00000000..00338536 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-B-xx.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *ediff-B-up[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 2 1", +/* colors */ +". c gray60", +"# c Gray75 s backgroundToolBarColor", +/* pixels */ +"###############", +"###############", +"###......######", +"###.......#####", +"###...##...####", +"###...###..####", +"###.......#####", +"###........####", +"###...###...###", +"###...####..###", +"###...###...###", +"###........####", +"###.......#####", +"###############", +"###############", +"###############" +}; diff --git a/xemacs-packages/etc/ediff/ediff-help.xbm b/xemacs-packages/etc/ediff/ediff-help.xbm new file mode 100644 index 00000000..b2c76efe --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-help.xbm @@ -0,0 +1,6 @@ +#define ediff-help_width 15 +#define ediff-help_height 15 +static char ediff-help_bits[] = { + 0x00,0x80,0xf0,0x83,0x0c,0x86,0xe4,0x8c,0x74,0x8d,0xb4,0x8c,0x58,0x86,0x20, + 0x83,0xa0,0x83,0xa0,0x81,0xc0,0x80,0x20,0x83,0x20,0x83,0xc0,0x81,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-help.xpm b/xemacs-packages/etc/ediff/ediff-help.xpm new file mode 100644 index 00000000..3964d9a2 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-help.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *help[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 3 1", +/* colors */ +". c #000000", +"b c Gray75 s backgroundToolBarColor", +"c c #ffff00", +/* pixels */ +"bbbbbbbbbbbbbbb", +"bbbb......bbbbb", +"bbb.ccccc..bbbb", +"bb.cc...cc..bbb", +"bb.c..bb.c..bbb", +"bb.c..b.cc..bbb", +"bbb..b.cc..bbbb", +"bbbbb.cc..bbbbb", +"bbbbb.c..bbbbbb", +"bbbbb.c..bbbbbb", +"bbbbbb..bbbbbbb", +"bbbbb.cc..bbbbb", +"bbbbb.cc..bbbbb", +"bbbbbb...bbbbbb", +"bbbbbbbbbbbbbbb" +"bbbbbbbbbbbbbbb" +}; diff --git a/xemacs-packages/etc/ediff/ediff-next.xbm b/xemacs-packages/etc/ediff/ediff-next.xbm new file mode 100644 index 00000000..240c6bfd --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-next.xbm @@ -0,0 +1,6 @@ +#define ediff-next_width 15 +#define ediff-next_height 15 +static char ediff-next_bits[] = { + 0x00,0x80,0x80,0x80,0x80,0x83,0x80,0x82,0xfe,0x8c,0x02,0x8a,0xfa,0xb7,0xfa, + 0xbf,0xfa,0x9f,0xfe,0x8f,0xfe,0x87,0x80,0x83,0x80,0x81,0x80,0x80,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-next.xpm b/xemacs-packages/etc/ediff/ediff-next.xpm new file mode 100644 index 00000000..b8718670 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-next.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * file[] = { +/* width height num_colors chars_per_pixel */ +"15 15 5 1", +" c Gray75 s backgroundToolBarColor", +". c black", +"X c white", +"o c black", +"O c black", +" ", +" . ", +" .. ", +" .X. ", +" .......XX. ", +" .XXXXXXXoX. ", +" .XooooooooX. ", +" .Xoooooooooo. ", +" .XooooooooO. ", +" .oOOOOOOoO. ", +" .......OO. ", +" .O. ", +" .. ", +" . ", +" ", +}; diff --git a/xemacs-packages/etc/ediff/ediff-prev.xbm b/xemacs-packages/etc/ediff/ediff-prev.xbm new file mode 100644 index 00000000..052f9620 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-prev.xbm @@ -0,0 +1,6 @@ +#define ediff-prev_width 15 +#define ediff-prev_height 15 +static char ediff-prev_bits[] = { + 0x00,0x80,0x00,0x81,0x80,0x81,0x40,0x81,0x20,0xbf,0x50,0xa0,0xe8,0xaf,0xfc, + 0xaf,0xf8,0xaf,0xf0,0xbf,0xe0,0xbf,0xc0,0x81,0x80,0x81,0x00,0x81,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-prev.xpm b/xemacs-packages/etc/ediff/ediff-prev.xpm new file mode 100644 index 00000000..c53e6a40 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-prev.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * left-arrow_xpm[] = { +/* width height num_colors chars_per_pixel */ +"15 15 3 1", +" c Gray75 s backgroundToolBarColor", +". c black", +"X c white", +" ", +" . ", +" .. ", +" .X. ", +" .XX...... ", +" .X.XXXXXX. ", +" .X.......X. ", +" ..........X. ", +" .........X. ", +" .......... ", +" ......... ", +" ... ", +" .. ", +" . ", +" ", +}; diff --git a/xemacs-packages/etc/ediff/ediff-quit.xbm b/xemacs-packages/etc/ediff/ediff-quit.xbm new file mode 100644 index 00000000..7c28d957 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-quit.xbm @@ -0,0 +1,6 @@ +#define ediff-quit_width 15 +#define ediff-quit_height 15 +static char ediff-quit_bits[] = { + 0x00,0x80,0x06,0xb0,0x1e,0x98,0x3c,0x8c,0x70,0x82,0xe0,0x83,0xc0,0x81,0xe0, + 0x83,0x70,0x86,0x38,0x8c,0x1c,0x88,0x1c,0x90,0x08,0x80,0x00,0x80,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-quit.xpm b/xemacs-packages/etc/ediff/ediff-quit.xpm new file mode 100644 index 00000000..37d51236 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-quit.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *delete[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 4 1", +/* colors */ +". c #808080", +"# c #800000", +"a c #ffffff", +"b c #c0c0c0", +/* pixels */ +"bbbbbbbbbbbbbbb", +"b##abbbbbbbb##a", +"b####abbbbb##ab", +"bb####abbb##abb", +"bbbb###ab#abbbb", +"bbbbb#####abbbb", +"bbbbbb###abbbbb", +"bbbbb#####abbbb", +"bbbb###ab##abbb", +"bbb###abbb##abb", +"bb###abbbbb#abb", +"bb###abbbbbb#ab", +"bbb#abbbbbbbbbb", +"bbb#abbbbbbbbbb", +"bbbbbbbbbbbbbbb", +}; diff --git a/xemacs-packages/etc/ediff/ediff-refine.xbm b/xemacs-packages/etc/ediff/ediff-refine.xbm new file mode 100644 index 00000000..059156be --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-refine.xbm @@ -0,0 +1,6 @@ +#define ediff-refine_width 15 +#define ediff-refine_height 15 +static char ediff-refine_bits[] = { + 0x00,0x80,0x80,0x80,0x84,0x90,0x8c,0x98,0x98,0x8c,0xf0,0x87,0xe0,0x83,0xe0, + 0x83,0xe0,0x83,0xf0,0x87,0x98,0x8c,0x8c,0x98,0x84,0x90,0x80,0x80,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-refine.xpm b/xemacs-packages/etc/ediff/ediff-refine.xpm new file mode 100644 index 00000000..c54eaff4 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-refine.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *help[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 2 1", +/* colors */ +"# c #000000", +"a c Gray75 s backgroundToolBarColor", +/* pixels */ +"aaaaaaaaaaaaaaa", +"aaaaaaa#aaaaaaa", +"aa#aaaa#aaaa#aa", +"aa##aaa#aaa##aa", +"aaa##aa#aa##aaa", +"aaaa#######aaaa", +"aaaaa#####aaaaa", +"aaaaa#####aaaaa", +"aaaaa#####aaaaa", +"aaaa#######aaaa", +"aaa##aa#aa##aaa", +"aa##aaa#aaa##aa", +"aa#aaaa#aaaa#aa", +"aaaaaaa#aaaaaaa", +"aaaaaaaaaaaaaaa", +}; diff --git a/xemacs-packages/etc/ediff/ediff-save-xx.xbm b/xemacs-packages/etc/ediff/ediff-save-xx.xbm new file mode 100644 index 00000000..b2527699 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-save-xx.xbm @@ -0,0 +1,6 @@ +#define disk-xx_width 15 +#define disk-xx_height 15 +static char disk-xx_bits[] = { + 0x00,0x00,0x0a,0x28,0x00,0x00,0x0a,0x28,0x00,0x00,0x0a,0x28,0x00,0x00,0xfa, + 0x2f,0x00,0x00,0x02,0x20,0x00,0x00,0x0a,0x29,0x00,0x00,0xf8,0x3f,0x00,0x00 + }; diff --git a/xemacs-packages/etc/ediff/ediff-save-xx.xpm b/xemacs-packages/etc/ediff/ediff-save-xx.xpm new file mode 100644 index 00000000..fcd14fbb --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-save-xx.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * disk[] = { +"15 15 5 1", +"X c Gray75 s backgroundToolBarColor", +"o c Gray60", +"O c Gray60", +"+ c Gray90", +"@ c Gray40", +"XXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXX", +"XoooooooooooooX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOoooooooooOoX", +"XoOOOOOOOOOOOoX", +"XoOoooooooooOoX", +"XoOo@@@@o++oOoX", +"XoOo@@@@o++oOoX", +"XoOo@@@@o++oOoX", +"XXooooooooooooX", +"XXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXX" +}; diff --git a/xemacs-packages/etc/ediff/ediff-save.xbm b/xemacs-packages/etc/ediff/ediff-save.xbm new file mode 100644 index 00000000..b53fedaa --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-save.xbm @@ -0,0 +1,6 @@ +#define disk-up_width 15 +#define disk-up_height 15 +static char disk-up_bits[] = { + 0x00,0x00,0xfe,0x3f,0x0a,0x28,0x0a,0x28,0x0a,0x38,0x0a,0x28,0x0a,0x28,0xfa, + 0x2f,0x02,0x20,0xfa,0x2f,0x0a,0x29,0x0a,0x29,0x0c,0x29,0xf8,0x3f,0x00,0x00 + }; diff --git a/xemacs-packages/etc/ediff/ediff-save.xpm b/xemacs-packages/etc/ediff/ediff-save.xpm new file mode 100644 index 00000000..a9a8e2b4 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-save.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * disk[] = { +"15 15 5 1", +"X c Gray75 s backgroundToolBarColor", +"o c black", +"O c Gray60", +"+ c Gray90", +"@ c Gray40", +"XXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXX", +"XoooooooooooooX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOo+++++++oOoX", +"XoOoooooooooOoX", +"XoOOOOOOOOOOOoX", +"XoOoooooooooOoX", +"XoOo@@@@o++oOoX", +"XoOo@@@@o++oOoX", +"XoOo@@@@o++oOoX", +"XXooooooooooooX", +"XXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXX" +}; diff --git a/xemacs-packages/etc/ediff/ediff-toggle-split-up.xbm b/xemacs-packages/etc/ediff/ediff-toggle-split-up.xbm new file mode 100644 index 00000000..ee1bbeee --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-toggle-split-up.xbm @@ -0,0 +1,6 @@ +#define ediff-toggle-split-up_width 15 +#define ediff-toggle-split-up_height 15 +static char ediff-toggle-split-up_bits[] = { + 0x00,0x80,0xfe,0x87,0xfe,0x87,0x00,0x80,0x00,0xb0,0x7e,0xb0,0x1e,0xb0,0x1e, + 0xb0,0x3e,0xb2,0x72,0xb3,0xe2,0xb3,0xc0,0xb3,0xc0,0xb3,0xf0,0xb7,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-toggle-split-up.xpm b/xemacs-packages/etc/ediff/ediff-toggle-split-up.xpm new file mode 100644 index 00000000..b41fff7c --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-toggle-split-up.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *ediff-toggle-split-up[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 3 1", +/* colors */ +"# c #000000", +"a c firebrick", +"f c Gray75 s backgroundToolBarColor", +/* pixels */ +"fffffffffffffff", +"faaaaaaaaaaffff", +"faaaaaaaaaaffff", +"fffffffffffffff", +"ffffffffffffaaf", +"f######fffffaaf", +"f####fffffffaaf", +"f####fffffffaaf", +"f#####fff#ffaaf", +"f#ff###ff#ffaaf", +"f#fff#####ffaaf", +"ffffff####ffaaf", +"ffffff####ffaaf", +"ffff######ffaaf", +"fffffffffffffff", +}; diff --git a/xemacs-packages/etc/ediff/ediff-update.xbm b/xemacs-packages/etc/ediff/ediff-update.xbm new file mode 100644 index 00000000..6d4598db --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-update.xbm @@ -0,0 +1,6 @@ +#define ediff-update_width 15 +#define ediff-update_height 15 +static char ediff-update_bits[] = { + 0x00,0x80,0x78,0x80,0xcc,0x99,0x04,0x9b,0x04,0x9c,0x04,0x9e,0x0c,0x9f,0x00, + 0x80,0x7c,0x98,0x3c,0x90,0x1c,0x90,0x6c,0x90,0xcc,0x99,0x00,0x8f,0x00,0x80 + }; diff --git a/xemacs-packages/etc/ediff/ediff-update.xpm b/xemacs-packages/etc/ediff/ediff-update.xpm new file mode 100644 index 00000000..adc802c7 --- /dev/null +++ b/xemacs-packages/etc/ediff/ediff-update.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *update[] = { +/* width height num_colors chars_per_pixel */ +" 15 15 3 1", +/* colors */ +". c #000000", +"a c #000080", +"c c Gray75 s backgroundToolBarColor", +/* pixels */ +"ccccccccccccccc", +"ccc.aaacccccccc", +"cc.acccaacccacc", +"ccaccccccacaacc", +"ccacccccccaaacc", +"ccaccccccaaaacc", +"cc.accccaaaaacc", +"ccccccccccccccc", +"ccaaaaacccca.cc", +"ccaaaaccccccacc", +"ccaaacccccccacc", +"ccaacaccccccacc", +"ccacccaaccca.cc", +"ccccccccaaa.ccc", +"ccccccccccccccc", +}; diff --git a/xemacs-packages/etc/enriched.doc b/xemacs-packages/etc/enriched.doc new file mode 100644 index 00000000..99301679 --- /dev/null +++ b/xemacs-packages/etc/enriched.doc @@ -0,0 +1,219 @@ +Content-Type: text/enriched +Text-Width: 80 + +bluewhite

enriched.el:
+blueWYSIWYG rich text editing for GNU Emacs +
bluewhiteINTRODUCTION + + +Emacs now has the ability to edit enriched text, which is text +containing faces, colors, indentation, and other properties. This +document is a quick introduction to some of the new features, and +is also an example file in the text/enriched format. + + +bluewhiteINSTALLATION and STARTUP + + +Most of the time, you need not do anything to get these features +to work. If you visit a file that has been written out in +text/enriched format, it will automatically be decoded, Emacs will +enter `enriched-mode' while visiting it, and whenever you save it +it will be saved in the same format it was read in. + +If you wish to create a new file, however, you will need to turn +on enriched-mode yourself: + + +M-x enriched-mode RET +Or, if you get a text/enriched file that Emacs does not +automatically recognize and decode, you can tell Emacs to decode +it (which also turns on enriched-mode automatically): + + +M-x format-decode-buffer RET text/enriched RET +bluewhiteWHAT IS ENCODED + + +Here is the current list of text-properties that are saved; they +are discussed in more detail below. Most of these can be added or +changed with the "Text Properties" menu, available under the +"Edit" item in the menu-bar, or on C-mouse-2 (Control + the middle +mouse button). + +Faces: default, bold, italic, underline, fixed, etc. + +Colors: redDarkSlateGrayanyDarkSlateGrayorangething yellowyourgreen screenblue light bluecanviolet display... +Sizes: things can get larger, smaller, much larger, and much + smaller. + +Newlines: Which ones are real ("hard") newlines, and which can be +changed to fit lines into the margins. + +Margins: can be indented on the left or right. + +Justification (whether lines should be flush with the left margin, +the right margin, fully justified, centered, or left alone). + +Excerpts: "For quoted material." +Read-only regions. + + +bluewhiteFACES and COLORS + + +You can add faces either with the menu or with M-g. The face is +applied to the current region. If you are using +`transient-mark-mode' and the region is not active, then the face +applies to whatever you type next. Any face can have colors, but +faces have no other attributes are put on the color submenus of +the "Text Properties" menu. + + +bluewhiteNEWLINES and PARAGRAPHS + + +Text/enriched format distinguishes between hard and soft newlines. +Hard newlines are used to separate paragraphs, or items in a list, +or anywhere that must be a line break no matter what the margins +are. Soft newlines are the ones inserted in order to fit text +between the margins. The fill and auto-fill functions insert soft +newlines as necessary, but hard newlines are only inserted by +direct request, such as using the return key or the C-o +(open-line) function. + + +bluewhiteINDENTATION + + +The fill functions also understand margins, which can be set +for any region of a document. In addition to the menu items, +which increase or decrease the margins, there are two commands +for setting the margins absolutely: C-c l (set-left-margin) +and C-c r (set-right-margin). +You can change indentation at any point in a paragraph, which +makes it possible to do interesting things like +hanging-indents: this paragraph was indented by selecting the +region from the second word to the end of the paragraph, and +indenting only that part. + +bluewhiteJUSTIFICATION + +Several styles of justification are possible, the simplest being unfilled. +This means that your lines will be left as you write them. +This paragraph is unfilled. + +The most common (for English) style is FlushLeft. This means +lines are aligned at the left margin but left uneven at the +right. + + + FlushRight makes each line flush with the right margin instead. + + +FlushBoth regions, which are sometimes called "fully justified" +are aligned evenly on both edges, so that the text on the page has +a smooth appearance as in a book or newspaper article. +Unfortunately this does not look as nice with a fixed-width font +as it does in a proportionally-spaced printed document; the extra +spaces that are needed on the screen can make it hard to +read. + +
Center + +
Finally, there is center justification. The normal + center-paragraph key, M-S, can be used to turn on center + justification in enriched-mode. + + M-j or the "Text Properties" menu also can be used to change + justification. + + +
Note that justification can only change at hard newlines, because +that is the unit over which filling gets done. + +
bluewhiteEXCERPTS + + +This is an example of an excerpt. You can use them for quoted +parts of other people's email messages and the like. It is just a +face, which is the same as the `italic' face by default. +bluewhiteTHE FILE FORMAT + +Enriched-mode docuemnts are saved in an extended version of a +format called text/enriched, which is defined as part of the MIME +standard. This means that your documents are transportable (even +through email) to many other systems. In the future other file +formats may be supported as well. + + +Since Emacs adds some non-standard features to the format (colors + +and read-only regions), not all systems will be able to recreate +all of the features of your document, but they will get as close +as possible. + + +The MIME standard is defined in internet RFC 1521; text/enriched +is defined in RFC 1563. Details on obtaining these documents via +FTP or email may be obtained by sending an email message to +rfc-info@isi.edu with the message body: + +help: ways_to_get_rfcs + + +See also the newsgroup comp.mail.mime. + + +bluewhiteCUSTOMIZATION + + +- The fixed and excerpt faces should be set to your liking. +- User-preference variables: default-justification, +enriched-verbose. - You can add annotations for your own text +properties by making additions to enriched-annotation-alist. +Note that the standard requires you to name your annotation +starting "x-" (as in "x-read-only"). Please send me any such +additions that you think might be of general interest so that +I can include them in the distribution. + + +bluewhiteTO-DO LIST + + +[Feel free to work on these and send me the results!] +- Be smarter about fixing malformed files. + +- Make the indentation work more seamlessly and robustly: + ++ Create an aggressive auto-fill function that will keep the +paragraph properly filled all the time, without slowing +down editing too much. ++ Refill after yank. + ++ Make deleting a newline also delete the indentation +following it. ++ Never let point enter indentation?? + +- Notice and re-fill when window changes widths (optionally). + +- Deal with the `category' text-property in a smart way. + +- Interface w/ GNUS, VM, RMAIL. Maybe Info too? + +- Support more formats: RTF, HTML... + + +bluewhiteFinal Notes: + + +This code and documentation is under development. Comments and +bug reports are welcome. + + +whiteblueBoris Goldowskylight blue light blue<blue +bluewhite April 1995blue +slightly augmented to match XEmacs version byblue +bluewhiteMichael Sperber < + +bluewhite April 1996 diff --git a/xemacs-packages/etc/python-modes/pydoc_lisp.py b/xemacs-packages/etc/python-modes/pydoc_lisp.py new file mode 100755 index 00000000..0ae5ac02 --- /dev/null +++ b/xemacs-packages/etc/python-modes/pydoc_lisp.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- Mode: Python; tab-width: 4 -*- +# +# SUMMARY: Produces Lisp lists of Python paths, pydoc keywords, modules and help topics. +# USAGE: l = Pydoc_Lisp() +# KEYWORDS: doc, emacs, lisp, pydoc +# +# AUTHOR: Bob Weiner +# ORG: Deepware +# +# ORIG-DATE: 18-Apr-01 at 12:08:46 +# LAST-MOD: 22-Apr-01 at 11:03:03 by Bob Weiner +# +# COPYRIGHT: Copyright (C) 2001 Bob Weiner +# Available for use and distribution under the terms of the Python license 2.0 or greater. +# +# DESCRIPTION: +""" +Produces Lisp lists of Python paths, pydoc keywords, modules and help topics. +See the doc for class Pydoc_Lisp for details. This provides the interface from +pydoc to the Emacs Lisp pydoc commands. +""" +# DESCRIP-END. + +## ------------------------------------------------------------------------ +## Required modules +## ------------------------------------------------------------------------ + +from string import find, join +import pydoc +import sys + +## ------------------------------------------------------------------------ +## Globals +## ------------------------------------------------------------------------ + +global pydoc_lisp_alist + +def pydoc_output_lisp(): + try: + if isinstance(pydoc_lisp_alist, Pydoc_Lisp): + # Reinitialize the lists + pydoc_lisp_alist.__init__() + else: + pydoc_lisp_alist = Pydoc_Lisp() + except NameError: + pydoc_lisp_alist = Pydoc_Lisp() + + +## ------------------------------------------------------------------------ +## Classes +## ------------------------------------------------------------------------ + +# This is defined as a class so that it may be easily added to pydoc.py +# rather than keeping it in this separate module. +class Pydoc_Lisp: + """ + Produces Lisp lists of Python paths, pydoc keywords, modules and help topics. + Results are stored in the class variables: keywords, modules, topics + and alist, the latter being an association list containing each of the former + three values. An instance prints as the value of `alist'. Call self.__init__() + if there is a need to reset the value of the module list. + """ + + ## Class variables + keywords = modules = paths = topics = alist = None + + def __init__(self): + Pydoc_Lisp.keywords = self._dict_to_lisp_list(pydoc.Helper.keywords) + Pydoc_Lisp.modules = self._get_modules_lisp() + Pydoc_Lisp.paths = self._get_paths_lisp() + Pydoc_Lisp.topics = self._dict_to_lisp_list(pydoc.Helper.topics) + Pydoc_Lisp.alist = '(("keywords" . %s)\n ("modules" . %s)\n ("paths" . %s)\n ("topics" . %s))' \ + % (Pydoc_Lisp.keywords, Pydoc_Lisp.modules, \ + Pydoc_Lisp.paths, Pydoc_Lisp.topics) + # Print the alist so the Lisp reader can evaluate it. + print Pydoc_Lisp.alist + + def __str__(self): + return Pydoc_Lisp.alist + + def _dict_to_lisp_list(self, dict): + keys = dict.keys() + keys.sort() + return '(("%s"))\n' % join(keys, '") ("') + + def _get_modules_lisp(self): + "Return a Lisp list of available Python module and package names." + module_dict = {} + + def callback(path, modname, desc, module_dict=module_dict): + if modname and modname[-9:] == '.__init__': + modname = 'Pkg-' + modname[:-9] + if find(modname, '.') < 0: + module_dict[modname] = 1 + + pydoc.ModuleScanner().run(callback) + return self._dict_to_lisp_list(module_dict) + + def _get_paths_lisp(self): + paths = sys.path[:] + try: + paths[paths.index('')] = '.' + except ValueError: + pass + return '(("%s"))\n' % join(paths, '") ("') + +## ------------------------------------------------------------------------ +## Program execution +## ------------------------------------------------------------------------ + +if __name__ == '__main__': + l = Pydoc_Lisp() diff --git a/xemacs-packages/info/bbdb.info b/xemacs-packages/info/bbdb.info new file mode 100644 index 00000000..3487162c --- /dev/null +++ b/xemacs-packages/info/bbdb.info @@ -0,0 +1,3626 @@ +This is bbdb.info, produced by makeinfo version 4.6 from bbdb.texinfo. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* BBDB: (bbdb). The Insidious Big Brother Database. +END-INFO-DIR-ENTRY + + This file documents the Insidious Big Brother Database + + This is edition $Revision: 1.9 $ of the BBDB User Manual for BBDB +version 2.34. + + Copyright (c) 1991-1994 Jamie Zawinski + + Copyright (c) 1997-1999 Matt Simmons + + Copyright (c) 2000-present The BBDB Development Team + + +File: bbdb.info, Node: Top, Next: Installation, Up: _ + +BBDB +**** + +BBDB is a rolodex-like database program for GNU Emacs. BBDB stands for +Insidious Big Brother Database, and is not, repeat, _not_ an obscure +reference to the Buck Rogers TV series. + + It provides the following features: + + * Integration with mail and news readers, with little or no + interaction by the user: + + * easy (or automatic) display of the record corresponding to + the sender of the current message; + + * automatic creation of records based on the contents of the + current message; + + * automatic addition of data to arbitrary fields of the record + corresponding to the sender of the current message. + + * Listing all records which match a regular expression; + + * Listing all records which match a regular expression in a + particular field (`company' or `notes,' for example); + +* Menu: + +* Installation:: Installation +* The BBDB:: Overview +* BBDB Mode:: BBDB Mode +* Interfaces:: Interfaces to various readers +* Reader-specific Features:: Features only available to specific readers +* Other Packages:: Using the BBDB with other packages +* Options:: Options +* Utilities:: Utilities +* Internals:: BBDB Internals +* Mailing Lists:: The BBDB mailing lists +* Changes:: New in this version +* The Latest Version:: Where to Get It +* The Future:: Known Bugs, the TODO list and EOL statements +* Thanks:: to the Ministry of Bugs + +* Concept Index:: Concept Index +* Variable Index:: Variable Index + + --- The Detailed Node Listing --- + +Installation + +* General Prerequisites:: General BBDB requirements + +File Installation +* Normal User:: "Normal" Installations +* XEmacs Package:: Installing as an XEmacs package + +Initial Configuration +* Initial Configuration:: How to initially set up the BBDB + +Manual initialization + +* Gnus Prep:: Initializing BBDB support for Gnus +* MH-E Prep:: Initializing BBDB support for MH-E +* RMAIL Prep:: Initializing BBDB support for RMAIL +* Sendmail Prep:: Initializing BBDB support for Sendmail +* VM Prep:: Initializing BBDB support for VM + +Other packages: + +* Message Prep:: Initializing BBDB support for Message mode +* Reportmail Prep:: Initializing BBDB support for Reportmail +* Supercite Prep:: Initializing BBDB support for Supercite +* Web Browser Prep:: Initializing BBDB support for Web Browsers + +The BBDB + +* Database Fields:: Description of database fields +* Basic Searching:: Basic database searching commands +* Advanced Searching:: Advanced database searching commands +* Manual Record Addition:: Adding records by hand + +Interfaces + +* Mail Reading Interfaces:: Mail Reading Interfaces +* News Reading Interfaces:: News Reading Interfaces +* Mail Sending Interfaces:: Mail Sending Interfaces + +Reader-specific Features + +* Gnus Features:: Gnus-specific Features +* VM Features:: VM-specific Features + +Gnus-specific Features + +* Gnus Scoring:: Store score adjustments in the BBDB +* Gnus Summary Buffer:: BBDB information in the Summary buffer +* GNUS Subject List:: BBDB information in the Subject List + +VM-specific features + +* VM Message Summary:: BBDB information in message summary + +Using the BBDB with other packages + +* Using Message Mode:: Using the BBDB with Message Mode +* Using Reportmail:: Using the BBDB with Reportmail +* Using Supercite:: Using the BBDB with Supercite +* Using Web Browsers:: Using the BBDB with Web Browsers + +Options + +* Customization Parameters:: Customization Parameters +* Customization Hooks:: Customization Hooks +* Predefined Hooks:: Predefined Hooks + +Utilities + +* bbdb-ftp:: Storing FTP sites in the BBDB +* bbdb-print:: Print the BBDB +* bbdb-snarf:: Record generation from raw text +* bbdb-srv:: External control of the BBDB + +Changes in this Version + +* Major Changes:: Major changes in this version +* Other Changes:: Not-so-major changes + +The Future + +* Known Bugs:: Known Bugs, and how to submit new ones +* TODO List:: The TODO List +* EOL Statements:: EOL (End Of Life) Statements + +_ + +* Top:: + + +File: bbdb.info, Node: Installation, Next: The BBDB, Prev: Top, Up: Top + +Installation +============ + +This program consists of several groups of files, organized by +directory: + + lisp - the main program code for the BBDB + tex - TeX support files for *Note bbdb-print::, the BBDB + printing utility + texinfo - the documentation files for the BBDB + utils - miscellaneous external utility programs + misc - things that don't fall into the above categories + bits - things that have been written as add-ons for BBDB + but have not yet been merged with the main codebase + +* Menu: + +* General Prerequisites:: General BBDB requirements + +File Installation +* Normal User:: "Normal" Installations +* XEmacs Package:: Installing as an XEmacs package + +Initial Configuration +* Initial Configuration:: How to initially set up the BBDB + + +File: bbdb.info, Node: General Prerequisites, Next: Normal User, Prev: Installation, Up: Installation + +General Prerequisites +--------------------- + +Various parts of the BBDB require extra packages to be available that +are not part of the BBDB distribution. Please note that with one +exception no extra packages (beyond those which ship with both GNU +Emacs and XEmacs) are required for the use of BBDB core +functionality.(1) This one exception applies to XEmacs 20.5 users - +the `xemacs-base' package must be installed for the correct operation +of the core BBDB functionality. The table below lists the requirements +of the various portions of the BBDB. Please note that the absence of +any of the below optional packages will not affect core BBDB +functionality. + +BBDB file Package needed GNU 19.34 GNU 20.2 XEmacs XEmacs + >=20.4 20.5 +`bbdb-ftp' EFS or B B B P + Ange-FTP +`bbdb-gnus' Gnus[1] B B B P +`bbdb-mhe' MH-E B B B P +`bbdb-reportmail' Reportmail B P[2] +`bbdb-sc' Supercite B B P +`bbdb-srv' `gnuserv' and B B + `itimer' +`bbdb-vm' VM[4] B P +`bbdb-w3' `browse-url' B B B P[3] + +NOTES: + 1. The old GNUS mail/newsreader should still work. Please keep in + mind that you have a relatively recent Emacs (GNU 19.34 or later, + XEmacs 19.15 or later), you are probably using Gnus. + + 2. As of this writing, Reportmail is available as part of the + `edit-utils' package. + + 3. As of this writing, `browse-url' is available as part of the + `mail-lib' package. + + 4. The source release of VM is currently required due to the use of + macros from the VM codebase in BBDB's VM integration. + + Please also note that the XEmacs package locations are as of this +writing. As the XEmacs 20.5 package system is still in development, the +locations may change without warning. + + ---------- Footnotes ---------- + + (1) "Core Functionality" is defined as the parts of the BBDB used to +implement basic record creation (`M-x bbdb-create') and searching (`M-x +bbdb'). + + +File: bbdb.info, Node: Normal User, Next: XEmacs Package, Prev: General Prerequisites, Up: Installation + +Normal User Installation +------------------------ + +Configuring the compilation process +----------------------------------- + +First of all, you should run the `configure' script at the toplevel of +the distribution. This script will perform a number of checks on your +system and generate the `Makefile''s accordingly. + + The `configure' script also comes with a number of options that lets +you customize the compilation process. These options are described +below where appropriate. + +Byte Compiling the Lisp files +----------------------------- + +First, you need to byte-compile the appropriate BBDB Lisp files. While +this is in theory an optional step, it is virtually required in +practice due to speed reasons. + + In order to byte-compile the lisp files, an Emacs of some sort must +be used. By default (at `configure' time), `emacs' and `xemacs' will be +tried in that order. If you want to use a special Emacs flavor (or if +you want to use `xemacs' at the first place), you should pass the +`--with-emacs=PROG' option to `configure'. + + In order to successfully compile the BBDB, the build process also +needs to know the location of the various optional packages. If the +directories containing these optional packages are in the default Emacs +search path (the `load-path' variable), no other changes need be made +for the build process to complete successfully. + + If the optional packages are not in the default search path, the +build process will not find them unless explicitly told of their +location(s). To tell the build process where to find Gnus, MH-E, +and/or VM, use the `configure' options `--with-gnus-dir=DIR', +`--with-mhe-dir=DIR', and/or `--with-vm-dir=DIR' variables +respectively. To tell the build process where to find any other +package(s), pass the directories containing the lisp files for the +package(s) to the `configure' option `--with-other-dirs=DIRS'. If +multiple directories are to be added, they should be separated by +spaces or colons, and should not be quoted. For example, to add the +`/p/local/elisp/footnote' and `/p/local/elisp/sc' directories, call the +`configure' script as follows: + + `configure --with-other-dirs=/p/local/elisp/footnote:/p/local/elisp/sc' + + After configuring, run one of the following commands: + + `make bbdb' - Build the core, mailer independent, components + `make gnus' - Core components plus `Gnus' support + `make mhe' - Core components plus `MH-E' support + `make rmail' - Core components plus `RMAIL' support + `make vm' - Build the core components with `VM' support + `make all' - Core components plus support for all mailers + listed above + + You can also combine the above `make' commands. For example, to +build the BBDB with support for `Gnus' and `VM', you can do so by +typing: + + make gnus vm + +Moving the files to their final destination +------------------------------------------- + +Lisp files +.......... + +As stated above, the `lisp' subdirectory contains the Emacs Lisp source +files for the BBDB. Therefore, these files must be in the Emacs +`load-path'. There are several ways of doing this, three of which are +described below: + + * Add the `lisp' directory from the source distribution to the + `load-path'. This will allow you to run the BBDB in-place. This + method is recommended for normal users or BBDB developers, + especially if disk usage is an issue. It is not recommended for + site-wide installations. + + * Link the `lisp' directory into your `site-lisp' directory. This is + for a site-wide installation, but it is subject to the following + caveat. If you link the `lisp' directory into `site-lisp', you + will make life more difficult for yourself down the road, as you + will not be able to make changes to the source directory (new + versions, patches, etc) without having an effect on other users + who now depend on it. This directory will automatically be added + to the `load-path' when Emacs starts. + + * Make a directory whose sole purpose in life is containing the + production copies of the BBDB source and byte-compiled source + files. Either put this directory under `site-lisp' (or put it + somewhere else and link it into `site-lisp'). This directory will + automatically be added to the `load-path' when Emacs starts. This + is the best of the three listed here, as it allows for a degree of + separation between the (possibly changing) source tree and the + production code. + +TeX files +......... + +The `tex' subdirectory contains the TeX support files for bbdb-print, +the BBDB printing utility (*Note bbdb-print::.). The three support +files, `bbdb-cols.tex', `bbdb-print.tex', and `bbdb-print-brief.tex', +must be placed in a directory that is either on the default TeX search +path or is listed in the `TEXINPUTS' environment variable. If neither +of these two options is taken, TeX will not be able to process the file +output by `bbdb-print'. + +texinfo files +............. + +The `bbdb.info' file in this directory contains the documentation for +the BBDB. This file should either be linked or copied to a directory +on the default path for the `info' program or listed in the `INFOPATH' +environment variable. + + +File: bbdb.info, Node: XEmacs Package, Next: Initial Configuration, Prev: Normal User, Up: Installation + +XEmacs Package Installation +--------------------------- + +NOTE: XEmacs packages are currently supported only under XEmacs +versions after and including 20.5. If you are not running such a +version of XEmacs, you should install the BBDB according to the +instructions in *Note Normal User::. + +Configuring / Byte Compiling +---------------------------- + +The configuration and byte-compilation procedures are the same as in the +Normal User installation. See *Note Normal User::. + +Moving the files to their final destination +------------------------------------------- + +Support is provided for the automatic installation of the BBDB in an +XEmacs package directory. The following `configure' options are +available for you: + +`--with-package-dir=DIR' + This option sets the root of the XEmacs package directory. By + default, `/usr/local/lib/xemacs/site-packages' is used. + +`--with-symlinks' + If this option is used, the installation will be done by making + symbolic links to the sources instead of copying the files. + +`--with-linkpath=PATH' + Without this option, the installation process uses the output of + `pwd' to determine the current directory. If something else should + be used, you should provide an alternate name for the BBDB toplevel + directory by using `--with-linkpath'. If, for example, `pwd' + returns `/p/local/elisp/bbdb', but you prefer to use + `/usr/local/elisp/bbdb/...' for the links, usr this: `configure + --with-linkpath=/usr/local/elisp/bbdb'. This option is ignored if + `--with-symlinks' is not used. + + To perform the (un)installation, use the command `make +(un)install-pkg'. This will compile the `lisp/auto-autoloads.el' file +and will install the appropriate files to the appropriate places. The +final installation tree will take the following form: + +`$(PACKAGEDIR)/' + + `lisp/' + + `bbdb/' + BBDB lisp source files. This directory contains a copy + of all `.el' and `.elc' files from the `lisp' source + directory, or is a symbolic link to it. + + `info/' + + `bbdb.info*' + BBDB documentation files. These are either copies of + the info files from the `texinfo' source directory, or + are symbolic links to them. + + `etc/' + + `bbdb/' + + `tex/' + BBDB support files for bbdb-print. This directory + contains a copy of the appropriate files from the + `tex' source directory, or is a symbolic link to it. + + `utils/' + BBDB miscellaneous utilities. This directory + contains a copy of the appropriate files from the + `utils' source directory, or is a symbolic link to + it. + + +File: bbdb.info, Node: Initial Configuration, Prev: XEmacs Package, Up: Installation + +Initial Configuration +--------------------- + +The simplest way to configure the BBDB is to include the following +forms in your Emacs configuration file: + + `(require 'bbdb)' + `(bbdb-initialize)' + + Note: The forms above replace the autoloads needed for previous +versions of the BBDB. + + This will set up the BBDB for basic querying and record manipulation +(the Core Functionality referred to in the Prerequisites section). It +will not enable any of the mailreader-, newsreader- or other +package-specific BBDB features. To enable some or all of these +features, the `(bbdb-initialize)' form can be enable as shown below. +Alternatively, the features can be enabled manually as described in the +following sections. + +Modifying `(bbdb-initialize)' +----------------------------- + +The `bbdb-initialize' function can be used to enable the various +package-specific BBDB functions. This feature activation is +accomplished through the passing of symbols which tell the function +which features to activate. These symbols are outlined below and in the +Emacs documentation for the `bbdb-initialize'(1) + +Initialization symbols for mail and news readers +................................................ + +`gnus' + Initialize support for Gnus(2). If you pass the `gnus' symbol, + you should probably also pass the `message' symbol. + +`mh-e' + Initialize support for the MH-E mail reader. + +`rmail' + Initialize support for the RMAIL mail reader. + +`sendmail' + Initialize support for sendmail (`M-x mail') + +`vm' + Initialize support for the VM mail reader.(3) + +Initialization symbols for other packages +......................................... + +`message' + Initialize support for Message mode (the mail composition program + included with Gnus). + +`reportmail' + Initialize support for the Reportmail mail notification package. + +`sc' + Initialize support for the Supercite message citation package. + Additional initialization is required for Supercite to work with + the BBDB. *Note Supercite Prep::. + +`w3' + Initialize support for Web browsers. + +Initialization example +...................... + +To initialize support for Gnus 5.5, Message mode, Supercite, and Web +browsers, the following forms would be used: + + (require 'bbdb) + (bbdb-initialize 'gnus 'message 'sc 'w3) + +Manual initialization +..................... + +If your initialization needs exceed those provided by +`bbdb-initialize', refer to the following sections for a description of +the procedures necessary for enabling BBDB support for the packages +listed above. The procedures described are the same as those carried +out by the `bbdb-initialize' function when passed the appropriate +symbols. That is, the procedure listed in the RMAIL Prep section below +is the same as than executed by `bbdb-initialize' when the `rmail' +symbol is passed. + +* Menu: + +Mail and News readers: + +* Gnus Prep:: Initializing BBDB support for Gnus +* MH-E Prep:: Initializing BBDB support for MH-E +* RMAIL Prep:: Initializing BBDB support for RMAIL +* Sendmail Prep:: Initializing BBDB support for Sendmail +* VM Prep:: Initializing BBDB support for VM + +Other packages: + +* Message Prep:: Initializing BBDB support for Message mode +* Reportmail Prep:: Initializing BBDB support for Reportmail +* Supercite Prep:: Initializing BBDB support for Supercite +* Web Browser Prep:: Initializing BBDB support for Web Browsers + + ---------- Footnotes ---------- + + (1) This documentation can be accessed by typing `C-h f +bbdb-initialize RET'. + + (2) If you are using GNUS (not Gnus), and if your GNUS version is +3.14 or older, use the `Gnus' (note the capitalization) symbol. + + (3) For the VM initialization to work properly, you must either call +`bbdb-initialize' with the `vm' symbol from within your VM +initialization file (`~/.vm'), or you must call `bbdb-insinuate-vm' +manually from within your VM initialization file. + + +File: bbdb.info, Node: Gnus Prep, Next: MH-E Prep, Prev: Initial Configuration, Up: Initial Configuration + +Initializing BBDB support for Gnus +.................................. + +To take advantage of the Gnus features of the BBDB, add one of the +following forms to your Emacs configuration file: + +For Gnus 3.14 or older: + + `(add-hook 'gnus-Startup-hook 'bbdb-insinuate-gnus)' + +For Gnus 3.15 or newer: + + `(add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)' + + `bbdb-insinuate-gnus' adds bindings for the default keys to Gnus and +configures Gnus to notify the BBDB when new messages are loaded. This +notification is required if the BBDB is to be able to display BBDB +entries for messages displayed in Gnus. + + +File: bbdb.info, Node: MH-E Prep, Next: RMAIL Prep, Prev: Gnus Prep, Up: Initial Configuration + +Initializing BBDB support for MH-E +.................................. + +To take advantage of the MH-E features of the BBDB, add the following +form to your Emacs configuration file: + + (add-hook 'mh-folder-mode-hook 'bbdb-insinuate-mh) + + `bbdb-insinuate-mh' adds bindings for the default keys to MH-E and +configures MH-E to notify the BBDB when new messages are loaded. This +notification is required if the BBDB is to be able to display BBDB +entries for messages displayed in MH-E. + + +File: bbdb.info, Node: RMAIL Prep, Next: Sendmail Prep, Prev: MH-E Prep, Up: Initial Configuration + +Initializing BBDB support for RMAIL +................................... + +To take advantage of the RMAIL features of the BBDB, add the following +form to your Emacs configuration file: + + (add-hook 'rmail-mode-hook 'bbdb-insinuate-rmail) + + `bbdb-insinuate-rmail' adds bindings for the default keys to RMAIL +and configures RMAIL to notify the BBDB when new messages are loaded. +This notification is required if the BBDB is to be able to display BBDB +entries for messages displayed in RMAIL. + + +File: bbdb.info, Node: Sendmail Prep, Next: VM Prep, Prev: RMAIL Prep, Up: Initial Configuration + +Initializing BBDB support for Sendmail +...................................... + +To take advantage of send-mail-mode (the one invoked with `M-x mail') +features of the BBDB, add the following form to your Emacs +configuration file: + + (add-hook 'mail-setup-hook 'bbdb-insinuate-sendmail) + + `bbdb-insinuate-sendmail' enables auto-completion in send-mail-mode. + + +File: bbdb.info, Node: VM Prep, Next: Message Prep, Prev: Sendmail Prep, Up: Initial Configuration + +Initializing BBDB support for VM +................................ + +To take advantage of the VM features of the BBDB, either add `'vm' to +the parameters of the `(bbdb-initialize)' form, or add the following +form to your `~/.vm' file: + + `(bbdb-insinuate-vm)' + + `bbdb-insinuate-vm' adds bindings for the default keys to VM and +configures VM to notify the BBDB when new messages are loaded. This +notification is required if the BBDB is to be able to display BBDB +entries for messages displayed in VM. + + +File: bbdb.info, Node: Message Prep, Next: Reportmail Prep, Prev: VM Prep, Up: Initial Configuration + +Initializing BBDB support for Message mode +.......................................... + +To allow the BBDB to be used in Message mode, add the following form to +your Emacs initialization file: + + `(bbdb-insinuate-message)' + + `bbdb-insinuate-message' adds a binding for `M-TAB' to Message mode. +This will enable completion of addressees based on BBDB records. See +*Note Using Message Mode:: for more details on the operation of Message +mode BBDB record completion. + + +File: bbdb.info, Node: Reportmail Prep, Next: Supercite Prep, Prev: Message Prep, Up: Initial Configuration + +Initializing BBDB support for Reportmail +........................................ + +To allow the Reportmail package to report information from BBDB records +for new mail, add the following form to your Emacs initialization file: + + `(bbdb-insinuate-reportmail)' + + `bbdb-insinuate-reportmail' adds to the `display-time-get-field' +function to allow access to BBDB records during new mail information +display. See *Note Using Reportmail:: for more details on the +operation of Reportmail with the BBDB. + + +File: bbdb.info, Node: Supercite Prep, Next: Web Browser Prep, Prev: Reportmail Prep, Up: Initial Configuration + +Initializing BBDB support for Supercite +....................................... + +To allow the BBDB to assist in the storage of Supercite citations, add +the following form to your Emacs initialization file: + + `(bbdb-insinuate-sc)' + + `bbdb-insinuate-sc' adds BBDB functions to two Supercite hooks - +`sc-post-hook' and `sc-attribs-postselect-hook'. See *Note Using +Supercite:: for more details on the operation of Supercite citation +management using the BBDB. + + Three other Supercite variables must be set/modified to allow the +BBDB to work with it. These variables are not automatically set as it +would be impossible to reliably set them without interfering with other +user customizations. The modifications are: + +`sc-preferred-attribution-list' + `"sc-consult"' should be added to the list. An example + configuration is: + + (setq sc-preferred-attribution-list + '("sc-lastchoice" "x-attribution" "sc-consult" + "initials" "firstname" "lastname")) + +`sc-attrib-selection-list' + The following form should be added to `sc-attrib-selection-list': + + '(("sc-from-address" + ((".*" . (bbdb/sc-consult-attr + (sc-mail-field "sc-from-address")))))) + +`sc-mail-glom-frame' + The following form should be added to `sc-mail-glom-frame', to + allow the retrieval of the name of a person who is a) in the BBDB + and b) has only included their net address in the message in + question. + + ("^$" (progn (bbdb/sc-default) + (list 'abort '(step . 0)))) + + An example configuration is as follows: + + `(setq sc-mail-glom-frame' + ` '((begin (setq sc-mail-headers-start (point)))' + ` ("^x-attribution:[ \t]+.*$" (sc-mail-fetch-field t) nil t)' + ` ("^\\S +:.*$" (sc-mail-fetch-field) nil t)' + ` ("^$" (progn (bbdb/sc-default)' + ` (list 'abort '(step . 0))))' + ` ("^[ \t]+" (sc-mail-append-field))' + ` (sc-mail-warn-if-non-rfc822-p (sc-mail-error-in-mail-field))' + ` (end (setq sc-mail-headers-end (point)))))' + + + The above is also documented in `bbdb-sc.el'. The +`bbdb/sc-setup-variables' function has been provided as an example for +Supercite variable initialization. Please note that while +`bbdb/sc-setup-variables' makes every attempt to safely configure the +Supercite variables, it will not always work. Specifically, the +variables `sc-attrib-selection-list' and `sc-mail-glom-frame' will not +be overridden if they have already been defined. + + +File: bbdb.info, Node: Web Browser Prep, Prev: Supercite Prep, Up: Initial Configuration + +Initializing BBDB support for Web Browsers +.......................................... + +To allow URLs to be added to BBDB records, add the following form to +your Emacs initialization file: + + `(bbdb-insinuate-w3)' + + `bbdb-insinuate-w3' adds the definition of `:' to the W3 keymap. + + The other `bbdb-w3' functions, specifically the passing of URLs from +BBDB records to Web browsers, do not require initialization within the +BBDB. They do, however, require the configuration of the `browse-url' +package so it knows to which Web browser URLs are to be passed. For +more details on the operation of `bbdb-w3', see *Note Using Web +Browsers::. + + +File: bbdb.info, Node: The BBDB, Next: BBDB Mode, Prev: Installation, Up: Top + +The BBDB +======== + +This section discusses the basics of the BBDB - an overview of the +database's layout, and a discussion of the basic BBDB manipulation +commands. + + The database itself lives in a file which is named by the variable +`bbdb-file'. If this variable is not set, the database is assumed to +be in `~/.bbdb'. + +* Menu: + +* Database Fields:: Description of database fields +* Basic Searching:: Basic database searching commands +* Advanced Searching:: Advanced database searching commands +* Manual Record Addition:: Adding records by hand + + +File: bbdb.info, Node: Database Fields, Next: Basic Searching, Prev: The BBDB, Up: The BBDB + +Database Fields +--------------- + +The database is organized as a set of records, where each record +corresponds to one person or organization. Each record has several +fields, and each field is of one of several types. Below, the built-in +types are listed, followed by a description of how and why some types +can be used more than once in a single record: + +Type Description Notes +`name' The name of this person, or none if Single value, single + the record corresponds to an instance. + organization. +`company'The name of this person's Single value, single + organization, or none. instance. +`AKA' A list of other names for this Multiple values through + person. commas. +`net' A list of this person's network Multiple values through + addresses. commas. +`address'A list of postal (physical) Multiple values through + addresses for this person. multiple occurences. +`phone' A list of telephone numbers for Multiple values through + this person. multiple occurences. +`notes' Random commentary. Multiple values through + multiple occurences. + + The field types listed above can be classified into four categories, +as indicated by the comments in the `Notes' column. + + Field types marked as "Single value, single occurrence" may only +occur once per record. Each occurrence can only have a single value. +For example, there will be only one field of type `name' in a record. +It will be named `name', and will contain a single value (the person's +name). + + The types marked as "Multiple values through commas" are essentially +the same as the single value, single occurrence field types, but with +one crucial difference: they can contain multiple values in the form of +a comma-separated list. So, for example, while a `name' field with a +value of "foo, bar" would be treated as if it contained the single value +"foo, bar", a `net' field with the same data would be thought of as +having two separate values - "foo" and "bar". As in the single +occurrence, single value field types, there will be only one occurrence +of each "Multiple values through commas" field type, and the occurrence +will have the same name as the type. + + The "Multiple values through multiple occurrences" field type is the +most flexible of the four listed here. There can be multiple +occurrences of each type. This type necessarily does not have the name +restriction imposed by the previous two types. For example, there can +be multiple fields of the `address' type, none of which have to be +named `address'. One could be named `home', and the other could be +named `work'. + + Special properties of the `notes' field type: All user-defined +fields that don't fit into the other predefined field types (`name', +`company', `AKA', `net', `address', and `phone') will be created as a +`notes'-type field. In addition, several of the user-defined field +names are "special". That is, the BBDB treats the values of these +"special" fields differently than it does other user-defined fields. +The "special" fields are: + +`attribution' + (Available only when the Supercite-specific BBDB functions have + been enabled) Used for the storage of Supercite attributions. For + initialization details, see *Note Supercite Prep::. For usage + details, see *Note Using Supercite::. The field used can be + changed by changing the value of `bbdb/sc-attribution-field'. + +`aka' + Used to store non-primary names associated with a given record. + +`face' + (XEmacs only) Used for the storage of image data. This data is to + be in the format output by `compface', and commonly found in + `X-Face:' headers in messages. If face support has been compiled + into XEmacs, the image contained in the `face' header will be + displayed when the record is viewed. + +`finger-host' + Address used in place of the listed net address for fingering the + entity indicated by the record. *Note BBDB Mode::. The field used + can be changed by changing the value of `bbdb-finger-host-field'. + +`gnus-score' + Gnus scoring adjustment for this person. For initialization + details, see *Note Gnus Prep::. For usage details, see *Note Gnus + Features::. The field used can be changed by changing the value of + `bbdb/gnus-score-field'. + +`mail-alias' + Value used instead of `name' for completion. *Note Mail Sending + Interfaces::. + +`mail-name' + (Available only when the Reportmail-specific BBDB functions have + been enabled) Used for the storage of non-default names to be + used in the reporting of new mail by Reportmail. For + initialization details, see *Note Reportmail Prep::. For usage + details, see *Note Using Reportmail::. + +`mark-char' + The field containing the character to be used for marking a given + poster in the Gnus Summary Buffer. For usage details, see *Note + Gnus Summary Buffer::. + +`tex-name' + The value of this field is used in place of the `name' field when + printing the database using `bbdb-print'. *Note bbdb-print::. + +`www' + This field contains the URL associated with the BBDB record. + Common uses are with `bbdb-snarf' (*note bbdb-snarf::) and the + BBDB/Web Browser functionality (for initialization details, see + *Note Web Browser Prep::. For usage details, see *Note Using Web + Browsers::). + + +File: bbdb.info, Node: Basic Searching, Next: Advanced Searching, Prev: Database Fields, Up: The BBDB + +Basic searching commands +------------------------ + +You can list the contents of the database with the command `M-x bbdb'. +You will be prompted for a regular expression, and all records which +match that regexp in the name, company, network address, or any notes +fields will be displayed. + + A narrower search may be made by using the commands `bbdb-name', +`bbdb-company,' `bbdb-net,' or `bbdb-notes'. These commands limit +their searches to the name, company, email address, and notes fields, +respectively. If these commands are given a prefix argument, the +listing displayed will be one line per entry; otherwise, the full +database entry will be shown on multiple lines. + + The functions described above are predefined to certain keys in the +`*BBDB*' buffer. *Note BBDB Mode::. for more details. + + The `bbdb-notes' command will prompt for the notes field to search +(`RET' for all). In this way you can limit your searches to the +contents of one particular user-defined notes field. (You can add +user-defined fields with the `bbdb-insert-new-field' command; *Note +BBDB Mode::.) + + +File: bbdb.info, Node: Advanced Searching, Next: Manual Record Addition, Prev: Basic Searching, Up: The BBDB + +Advanced searching commands +--------------------------- + +The following functions can be used to search for records based on +creation and/or modification dates. These functions will match records +that have `timestamp' and/or `creation-date' fields (as appropriate. +*Note Predefined Hooks::. for more information on these fields, which +are created by default. + +`bbdb-timestamp-older' + Display all records modified before a given date. If this + function is called interactively, it will prompt for a date. If + it is being called non-interactively, the date should be provided + as a string in `yyyy-mm-dd' format. + +`bbdb-timestamp-newer' + Display all records modified after a given date. If this function + is called interactively, it will prompt for a date. If it is + being called non-interactively, the date should be provided as a + string in `yyyy-mm-dd' format. + +`bbdb-creation-older' + Display all records created before a given date. If this function + is called interactively, it will prompt for a date. If it is + being called non-interactively, the date should be provided as a + string in `yyyy-mm-dd' format. + +`bbdb-creation-newer' + Display all records created after a given date. If this function + is called interactively, it will prompt for a date. If it is + being called non-interactively, the date should be provided as a + string in `yyyy-mm-dd' format. + +`bbdb-creation-no-change' + Display all records that have not been changed since creation. + + +File: bbdb.info, Node: Manual Record Addition, Prev: Advanced Searching, Up: The BBDB + +Manual record addition +---------------------- + +There are several ways to add new entries to the Insidious Big Brother +Database; the most straightforward is to use `M-x bbdb-create', which +will prompt you for all relevant information. However, the easiest way +is to allow them to be added automatically by one of the mail or +news-reading interfaces (*Note Interfaces::.). + + There is als `bbdb-snarf' (*Note bbdb-snarf::), which will attempt +to create a record from a text block. Note that this depends on +particular formatting and may not do exactly what you want. + + +File: bbdb.info, Node: BBDB Mode, Next: Interfaces, Prev: The BBDB, Up: Top + +BBDB Mode +========= + +Functions bound to keys in BBDB Mode +------------------------------------ + +When the `*BBDB*' buffer is active (either summoned by one of the +commands in the previous section [*Note The BBDB::.] or by your mail or +news program), a variety of commands become available for database +manipulation. Some of the commands listed below take numeric arguments. +These arguments can be generated by entering the number before pressing +the key(s) corresponding to the desired command. The output (if any) of +the listed commands will be displayed in the `*BBDB*' buffer, and can +be navigated through using the usual cursor motion commands. + +`e' + (`bbdb-edit-current-field') Edit the field on the current line. + If the cursor is in the middle of a multi-line field, such as an + address or comments section, then the entire field is edited, not + just the current line. + +`;' + (`bbdb-edit-notes') A shortcut for editing the NOTES field. + +`d, C-k' + (`bbdb-delete-current-field-or-record') Delete the field on the + current line. If the current line is the first line of a record, + the BBDB will, after prompting the user, delete the entire record + from the database. This may also be applied to multiple records + at once by `*'. + +`C-o' + (`bbdb-insert-new-field') Inserts a new field into the current + record. You are prompted (with completion) for the type of field + to insert (phone, address, notes, etc); if the string you type is + not a known field type, you will be asked whether to add a new + field with the entered name of type `notes'. + + If you are inserting a new phone-number field, you can control + whether it is a North American or European phone number by + providing a prefix argument. A prefix arg of `^U' means it's to + be a euronumber, and any other prefix arg means it's to be a a + structured North American number. If no prefix argument is + supplied, the style used is controlled by the variable + `bbdb-north-american-phone-numbers-p'. + +`C-x C-t' + (`bbdb-transpose-fields') This is like the `transpose-lines' + command, but it is for BBDB fields. If the cursor is on a field of + a BBDB record, that field and the previous field will be + transposed. + + With non-zero numeric argument ARG, the previous field is moved + past ARG fields. With argument 0, the field indicated by point is + interchanged with the one indicated by mark. + + Both fields must be in the same record, and must be of the same + basic type (that is, you can use this command to change the order + in which phone-number fields are listed, but you can't use it to + make an address appear before a phone number; the order of field + types is fixed.) + +`n, p' + (`bbdb-next-record', `bbdb-prev-record') Move to the next and + previous displayed record, respectively. + +`t' + (`bbdb-toggle-records-display-layout') Toggles the display layout + of a record. With a numeric argument of 0, the current record + will be made displayed in one line layout; with any other + argument, the current record will be shown in multi-line layout. + + If `*t' is used instead of simply `t', then the state of all + records will be changed instead of just the one at point. In this + case, a numeric argument of 0 means that all records will + unconditionally be made one-line layout; any other numeric + argument means that all of the records will unconditionally be + shown expanded; and no numeric argument means that the records are + made to be in the opposite state of the record under point. + +`T' + (`bbdb-display-record-completely') Show all the fields of the + current record. The display layout `full-multi-line' is used for + this. + +`o' + (`bbdb-omit-record') Removes the current record from the display, + but does not delete it from the database; it merely makes it seem + as if the most recent search had not matched this record. With a + numeric argument, omit the next N records. With a negative + argument, go backwards. + +`m' + (`bbdb-send-mail') Begin composing mail to the person represented + by the current record. The first email address is used. + Normally, the mail-sending package which is used is determined by + which mail-reading package is loaded; that is, if MH-E is loaded, + then `mh-send' will be used; if VM is loaded, then `vm-mail' is + used; if message is loaded, then it is used; otherwise, `mail' is + used. You can override this by setting the variable + `bbdb-send-mail-style' to one of the symbols `vm', `mh', + `message', or `mail'. + + If `*m' is used instead of simply `m', then mail will be sent to + all of the folks listed in the `*BBDB*' buffer instead of just the + person under point. + + This function does not at present use the facility provided by + `compose-mail' and `mail-user-agent'. In a future version of the + BBDB, it will. + +`s, C-x C-s' + (`bbdb-save-db') Saves the BBDB file to disk. + +`r' + (`bbdb-refile-record') Merge the current record into some other + record; that is, delete the record under point after copying all + of the data within it into some other record. this is useful if + you realize that somehow a redundant record has gotten into the + database, and you want to merge it with another. + + If both records have names and/or companies, you are asked which + to use. Phone numbers, addresses, and network addresses are + simply concatenated. The first record is the record under the + point; the second is prompted for. Completion behavior is as + dictated by the variable `bbdb-completion-type'. + +`M-d' + (`bbdb-dial') This command will attempt to dial the phone number + currently at point, or if point is at the start of a record, the + first phone number in the record. An extension, if present, is + disregarded. + + The method of dialling is controlled by `bbdb-modem-dial'. If this + variable is nil, the BBDB will play touchtones corresponding to the + number to be dialled. Otherwise, this variable is treated as a + modem command string to be prepended to the number prior to + feeding it to `bbdb-modem-device'. + + The BBDB plays touchtones using `bbdb-sound-player' to play the + sounds and the elements of `bbdb-sound-files' as the audio to be + played. The first ten elements of `bbdb-sound-files' correspond to + the touchtones for the digits `0' to `9', while the eleventh and + twelfth elements correspond to `#' and `*' respectively. The + default configuration assumes a Solaris[tm] installation with the + demonstration sound files in `/usr/demo/SOUND/sounds'. + + The actual number dialled depends on the following variables: + + `bbdb-dial-local-prefix-alist' + This is a list of (SEXPR REPLACEMENT) pairs. SEXPR is + evaluated to produce a regular expression which is then + applied to the number. If it matches, whatever it matches is + replaced by REPLACEMENT. The match and replace is performed + using each item in the list that matches, in sequence, so + that the output from one item may become input to another. + The default value for this variable is to remove + `(bbdb-default-area-code)' (i.e. the value of that variable, + in parenthesis) from the start of the number to be dialled. + + Note: If this procedure produces a transformed number then no + further modifications (such as prefix additions, below) will + be made to the number before dialling. + + Using a prefix argument to `bbdb-dial' disables the + processing of this variable. The other modifiers, below, are + not affected by this. + + `bbdb-dial-local-prefix' + If the number to be dialled starts with a zero, it is deemed + to be a local number, and `bbdb-dial-local-prefix' is + prepended to it (see note above concerning + `bbdb-dial-local-prefix-alist' processing, however). + + `bbdb-dial-long-distance-prefix' + If the number to be dialled starts with a plus sign (+), it + is deemed to be a long distance number, and + `bbdb-dial-long-distance-prefix' is prepended to it (see note + above concerning `bbdb-dial-local-prefix-alist' processing, + however). + + +`f' + (`bbdb-finger') This command fingers the network address of a + BBDB record. If this command is executed from the `*BBDB*' buffer, + it fingers the network address of the record which is at point; + otherwise, it prompts in the minibuffer (with completion) for a + user to finger. With a numeric prefix argument, it fingers the + Nth network address of the current record; with a prefix argument + of `^U', it fingers all of them. The `*finger*' buffer is filled + asynchronously, meaning that you don't have to wait around for it + to finish; but fingering another user before the first finger has + finished could have unpredictable results. + + If this command is executed from the `*BBDB*' buffer, it may be + prefixed with `*' (as in `*f' instead of simply `f'), meaning to + finger all of the users currently listed instead of just the one + under point. The numeric prefix argument has the same + interpretation. + + You can define a special network address to "finger" by defining a + field `finger-host'. The name of the field to be fingered can be + changed by setting `bbdb-finger-host-field'. + +`q' + (`bbdb-bury-buffer') Hides the `*BBDB*' buffer. Note: This + command does not kill the `*BBDB*' buffer. + +`?' + (`bbdb-help') This displays a one-line help message in the + minibuffer, showing some of the most common bbdb-mode commands. + +`i' + (`bbdb-info') This documentation is displayed. Please note that + either `bbdb' or `bbdb.info' must be installed in one of the info + directories known to Emacs for this command to work. + + `bbdb-info-file' + If this documentation is not installed in the standard Info + directory, then you should set this variable to the name of + the texinfo-formatted version of this file; the `bbdb-info' + command will use this file instead. + +`W' + (`bbdb-www') Displays the Web page listed in the `www' field of + the current record. *Note Using Web Browsers::. + +`P' + (`bbdb-print') Creates a TeX file that contains a pretty-printed + version of BBDB records. If prefixed by `*', only the records + currently displayed will print. *Note bbdb-print::. + +`h' + Moves point to another window via the `other-window' function. + +`c' + (`bbdb-create') Create a new database record from information + supplied by the user. + +`C' + (`bbdb-changed') Display all records that have been changed since + the last time the database was saved. + +`b' + (`bbdb') Begin a new database search. The results of the new + search will be displayed in place of the results of the old search. + +`S a, S c, S o, S n' + (`bbdb-net', `bbdb-company', `bbdb-notes', `bbdb-name') + Begin a new database search. This search will be limited to the + net address, company, notes, or name fields, respectively, of + database records. *Note Basic Searching::. for more details. + +`*' + `bbdb-append-records' will make the next display/search command to + append its results to the BBDB buffer instead of replacing its + content. + + With an prefix arg (C-u) toggle between always append and no + append. With an prefix arg that is a positive number append will + be enabled for that many times. With any other argument append + will be enabled once." + + +Other database manipulation functions +------------------------------------- + +`bbdb-kill-older' + If called interactively (or with a single argument - a date in + `yyyy-mm-dd' format), it will kill all records that were last + modified before the given date as determined by the `timestamp' + field. *Note Predefined Hooks::. If called non-interactively + with a date (in `yyyy-mm-dd' format), a comparison function and an + action function, the comparison function is applied to the + `timestamp' field of all records, and the action function applied + to those for whom the comparison function returns true. If `nil' + is supplied as the comparison function, `string-lessp' is used. + + + +File: bbdb.info, Node: Interfaces, Next: Reader-specific Features, Prev: BBDB Mode, Up: Top + +Interfaces +========== + +The BBDB interfaces itself with several message-handling packages, but +certain parameters control its behavior depending on whether it is +being used from within a mail reader or a news reader. + + In all of these packages, two new keybindings will be added: + +`:' + (`bbdb/package-show-sender') Displays the BBDB entry corresponding + to the author of the current message. If there is none, you will + be asked whether to create one. The function called is + `bbdb/package-show-sender', where `package' is either `gnus', + `mh', `rmail', or `vm', depending on the mail or news program + being used when the command is invoked. + +`;' + (`bbdb/package-annotate-sender') Lets you edit the `notes' field + of the BBDB record corresponding to the sender of the current + message. If there is no record for the current author, you will be + asked whether to create one. The function called is + `bbdb/package-annotate-sender', where `package' is either `gnus', + `mh', `rmail', or `vm', depending on the mail or news program + being used when the command is invoked. + + These keybindings (and several other features) will not be available +unless you call the appropriate "insinuation" function; *Note +Installation::. + + It is possible to configure BBDB so that it automatically creates a +record when it sees a message from a person who is not in the database. +It is also possible to have text automatically added to the notes field +of the corresponding record depending on the contents of the message +headers. *Note Customization Hooks::. + +* Menu: + +* Mail Reading Interfaces:: Mail Reading Interfaces +* News Reading Interfaces:: News Reading Interfaces +* Mail Sending Interfaces:: Mail Sending Interfaces + + +File: bbdb.info, Node: Mail Reading Interfaces, Next: News Reading Interfaces, Prev: Interfaces, Up: Interfaces + +Mail Reading Interfaces +----------------------- + +There are BBDB interfaces for the following mail readers: + + * Gnus, a news- and email- reader written by Lars Magne Ingebrigtsen + (based on GNUS by Mansanobu Umeda). + + * MH-E, the Emacs interface to Mail Handler (MH), from the standard + emacs library, but packaged separately from XEmacs since version + 20.4. + + * RMAIL, from the standard emacs library (packaged separately for + XEmacs users as of 20.4); + + * View Mail, by Kyle Jones, version 5.31 or newer; + + +File: bbdb.info, Node: News Reading Interfaces, Next: Mail Sending Interfaces, Prev: Mail Reading Interfaces, Up: Interfaces + +News Reading Interfaces +----------------------- + +There are BBDB interfaces for the following news readers: + + * GNUS, a newsreader written by Masanobu Umeda. + + * Gnus, the modern news- and email-reading incarnation of GNUS. + Gnus is written by Lars Magne Ingebrigtsen. + + +File: bbdb.info, Node: Mail Sending Interfaces, Prev: News Reading Interfaces, Up: Interfaces + +Mail Sending Interfaces +----------------------- + +When sending mail, the keystroke `M-TAB' is bound to the function +`bbdb-complete-name'. This will take the string that you have typed +(from point back to the preceding colon, comma, or the beginning of the +line) and will complete that against the contents of the database. +What you have typed may be an initial subsequence of a person's full +name or network address; if it completes ambiguously, then what you +have typed will be replaced with the common portion of the matches. +Typing `M-TAB' again will show a list of possible completions. If it +completes unambiguously, then an address will be inserted. The variable +`bbdb-completion-type' controls whether completion is done on real +names, or network addresses, or both. The address inserted is normally +of the form `User Name '; however, if `User Name' has an +address of the form `', only the +`' portion is inserted. This can be overridden by setting +`bbdb-dwim-net-address-allow-redundancy' to `t'. + + This binding is automatically set by the various insinuation +functions documented earlier in this manual. (*Note Initial +Configuration::.) Briefly, the forms for these functions are: + +Gnus + `(add-hook 'gnus-Startup-hook 'bbdb-insinuate-gnus)' for Gnus 3.14 + or older + `(add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)' for Gnus 3.15 + or newer + +MH-E + `(add-hook 'mh-folder-mode-hook 'bbdb-insinuate-mh)' + +RMAIL + `(add-hook 'rmail-mode-hook 'bbdb-insinuate-rmail)' + +sendmail + `(add-hook 'mail-setup-hook 'bbdb-insinuate-sendmail)' + +VM + `(bbdb-insinuate-vm)' Add to `~/.vm' file + +The above forms should be added to your Emacs initialization file, +except where otherwise noted. + + You can control what "real name" is inserted with the `mail-alias' +field: if a record has a `mail-alias' field, then that is used instead +of their `name' field. + + If the variable `bbdb-completion-display-record' is true (the +default) then when you successfully complete an address with `M-TAB', +the corresponding record will be appended to the `*BBDB*' buffer. The +buffer will not be displayed if it is not already visible, but the +record will be displayed there. + + When sending mail, you can use the command `bbdb-yank-addresses' to +CC the current message to the people currently displayed in the +`*BBDB*' buffer. This is useful if you are in the midst of sending or +replying to a message, and you decide to add some recipients. You can +use one of the `M-x bbdb' commands to display the set of people that +you want to CC the message to, and then execute this command to add +them to the list. + +Mailing Lists and Mail Aliases +------------------------------ + +If you are using Jamie Zawinski's `mail-abbrevs.el' package, which uses +the word-abbrev mechanism for mail aliases, then you can store your +mail aliases in the BBDB instead of duplicating the information +elsewhere. + + If you want a mail alias to be defined for a person, simply add a +`mail-alias' field to their record. You may have multiple aliases for +the same person; simply separate them with commas. + + For convenience there is the function `bbdb-add-or-remove-mail-alias' +bound to `a' which adds an alias to one or multiple records when +prefixed by a `*'. Called with a prefix argument `C-u' it will remove +the given alias. + + If more than one person has the same mail-alias, then that alias +expands to the addresses of all of those people; in this way you can +maintain mailing lists within the BBDB. + + When you want to group aliases as in `.mailrc' you may just retained +the group aliases in your `.mailrc'. + + To actually define the aliases which are stored in the BBDB, call the +function `bbdb-define-all-aliases' from your `mail-setup-hook' (or +`message-setup-hook' if you use Message mode coming with Gnus). This +will search the database, and call `define-mail-alias' to define each +of the resulting aliases. + + +File: bbdb.info, Node: Reader-specific Features, Next: Other Packages, Prev: Interfaces, Up: Top + +Reader-specific Features +======================== + +There are features of the BBDB that are available only for specific +mail- and news-readers. These features are described below. + + The headers which are parsed for email addresses and what records are +displayed can be controlled by the following variables: +`bbdb-get-addresses-from-headers' controls which headers are parsed for +sender addresses when calling the show-sender function of your MUA. +`bbdb-get-addresses-to-headers' controls which headers are parsed for +recipients addresses when calling the show-all-recipients function of +your MUA. When using the pop up feature it will search for the +addresses in `bbdb-get-addresses-headers' and display them. By default +it will list only the first address, but by setting +`bbdb-get-only-first-address-p' to `nil' one will will get records for +all addresses. + + If there is no MUA specific variable for ignoring certain addresses +then those addresses matching `bbdb-user-mail-names' will be ignored. + + BBDB adds the bindings `:' for showing all senders and `;' for +editing the notes of the sender. + +* Menu: + +* Gnus Features:: Gnus-specific Features +* VM Features:: VM-specific Features + + +File: bbdb.info, Node: Gnus Features, Next: VM Features, Prev: Reader-specific Features, Up: Reader-specific Features + +Gnus-specific Features +---------------------- + +The BBDB can be used to provide score information, or to integrate +database information into the Gnus Summary buffer or the GNUS Subject +List. + +* Menu: + +* Gnus Scoring:: Store score adjustments in the BBDB +* Gnus Summary Buffer:: BBDB information in the Summary buffer +* GNUS Subject List:: BBDB information in the Subject List + + +File: bbdb.info, Node: Gnus Scoring, Next: Gnus Summary Buffer, Prev: Gnus Features, Up: Gnus Features + +Scoring +....... + +The BBDB can provide scoring information to Gnus in one of two ways. + + 1. Articles whose authors appear in the BBDB and who have + `gnus-score' fields will have their scores adjusted by the value + contained in that field. + + 2. Articles whose authors appear in the BBDB but who do not have + `gnus-score' fields will have their scores adjusted by + `bbdb/gnus-score-default'. If `bbdb/gnus-score-default' is `nil', + no score adjustment will be made. + + The BBDB by default searches the field contained in +`bbdb/gnus-score-field' for score values. To have the BBDB use a +different field, change the value of this variable. + + To enable BBDB-assisted scoring, add the `bbdb/gnus-score' function +to `gnus-score-find-score-files-function'. Assuming that you want to +preserve the default value of this variable, use a form similar to the +following: + + (setq gnus-score-find-score-files-function + '(gnus-score-find-bnews bbdb/gnus-score)) + + Note: The default value in Gnus 5.5 is `gnus-score-find-bnews'. +Check your configuration before using the above code, as your values may +be different. + + +File: bbdb.info, Node: Gnus Summary Buffer, Next: GNUS Subject List, Prev: Gnus Scoring, Up: Gnus Features + +Gnus Summary Buffer Enhancements +................................ + +Gnus can use the BBDB to do one of two things: + + * Mark authors in the Summary Buffer who have records in the BBDB + with a user-defined mark character. See Marking Posters, below. + + * For authors in the Summary Buffer who also have records in the + BBDB, replace their name as listed in the Summary Buffer with + their name as stored in the BBDB. See Using Names from the BBDB, + below. + +Marking Posters +............... + +Authors with records in the BBDB can be marked either with a +user-defined mark character, or with a default one. The marking is +enabled by the use of a Gnus user format code, as determined by +`bbdb/gnus-summary-in-bbdb-format-letter'. This variable, which +defaults to `b', is used to create a format code which is intended for +use in `gnus-summary-line-format'. The format code is created by +concatenating `%u' with the value of +`bbdb/gnus-summary-in-bbdb-format-letter'. In the default case this +results in the creation of the format code `%ub'. + + Posts are marked as follows: If the record for the poster has the +field indicated in `bbdb-message-marker-field' (the default is +`mark-char'), the value of that field is used as the mark character.(1) +If no such field is present, the value of +`bbdb/gnus-summary-known-poster-mark' will be used instead. If the +author is not in the BBDB, a space will be used as the mark character. + +Using Names from the BBDB +......................... + +The names reported for authors of posts in the Summary buffer can be +altered to conform to the values present in their respective BBDB +records (if any). This rewriting is enabled by the use of a Gnus user +format code, as determined by `bbdb/gnus-summary-user-format-letter'. +This variable, which defaults to `B', is used to create a format code +which is intended for use in `gnus-summary-line-format'. The format +code is created by concatenating `%u' with the value of +`bbdb/gnus-summary-user-format-letter'. In the default case this +results in the creation of the format code `%uB'. This format code is +intended to replace the format code previously used in the Summary +buffer format line to indicate the author and/or net address (usually +`%a', `%n', and/or `$N'). + + The effects of this format code are in two independent parts - the +marking of known posters, and the rewriting of posters names. The +first, the marking of posters, occurs only when +`bbdb/gnus-summary-mark-known-posters' is `t' (the default) and the +posters have entries in the BBDB. When this variable is true, the +marking occurs as described in the previous section, Marking Posters, +above. + + The poster name rewriting is done for all posters - not just for +those with records in the BBDB. That said, rewriting rules for posters +in the BBDB are more flexible than for those not listed. The rewriting +is governed by two variables, as described below. + + `bbdb/gnus-summary-prefer-real-names' can have one of three values - +`t', `bbdb', or `nil'. In general, this variable governs the +preference between net addresses and names. If it is `t', the name (if +any) will be used. If `nil', the net address will be used. The third +value, `bbdb', can be used as a method for distinguishing between +authors with records in the BBDB and those without. If the variable is +set to `bbdb', the name from the BBDB record will be used if the author +has a record in the BBDB. If the author is not in the BBDB, the net +address from the message will be printed. This variable makes little +sense if `bbdb/gnus-summary-prefer-bbdb-data' is `nil', as no names +will be printed in the Summary buffer in this case - only net addresses. + + `bbdb/gnus-summary-prefer-bbdb-data' is used to (dis)allow use of +the BBDB for author data retrieval. If it is `t', data from the BBDB +will be used if available. If it is `nil', data from the BBDB will not +be used. + +In the following examples, assume the following: + + 1. Message: `From: Jamie ' + BBDB: No record + + 2. Message: `From: Matt ' + BBDB: Name: `Matthew', Net: `simmonmt@purdue.edu' + +`bbdb/gnus-summary-prefer-bbdb-data' `t' `t' `nil' +`bbdb/gnus-summary-prefer-real-names' `t' `bbdb' `t' +Printed in Summary buffer for + Case 1 Jamie jwz@netscape.com Jamie + Case 2 Matthew Matthew Matt + + ---------- Footnotes ---------- + + (1) While it is possible to put a multi-character mark in +`bbdb-message-marker-field' and/or in +`bbdb/gnus-summary-known-poster-mark', the resulting summary buffer +will be misaligned as a result. This misalignment will result from fact +that at this time the character used to indicate posts whose authors are +not in the BBDB is always a single character, and cannot be changed. + + +File: bbdb.info, Node: GNUS Subject List, Prev: Gnus Summary Buffer, Up: Gnus Features + +GNUS Summary Buffer Enhancements +................................ + +This section is remarkably terse, as I don't have a copy of GNUS. If +anybody can provide more descriptive information, please let me know. + + (autoload 'bbdb/gnus-lines-and-from "bbdb-gnus") + (setq gnus-optional-headers 'bbdb/gnus-lines-and-from) + +`bbdb/gnus-mark-known-posters' + If `t' (the default), then the GNUS subject list will contain an + indication of those messages posted by people who have entries in + the Insidious Big Brother Database (they will be marked with an + asterisk.) + + You can change the character used to mark records on a + record-by-record basis by adding a `mark-char' property to the + record, whose value is be the string to display (preferably one + character.) + +`bbdb/gnus-header-prefer-real-names' + Default: `nil'. if `t', then the GNUS subject list will display + real names instead of network addresses. + +`bbdb/gnus-header-show-bbdb-names' + Default: `t'. If both this variable and the + `bbdb/gnus-header-prefer-real-names' variable are true, then for + news messages from people who are in your database, the name + displayed will be the primary name from the database, rather than + the one from the `From:' line of the message. This doesn't affect + the names of people who aren't in the database, of course. + +`bbdb/gnus-lines-and-from-length' + Default: 18. The number of characters used to display `From:' + info in GNUS, if you have set `gnus-optional-headers' to + `bbdb/gnus-lines-and-from'. + + +File: bbdb.info, Node: VM Features, Prev: Gnus Features, Up: Reader-specific Features + +VM-specific features +-------------------- + +The BBDB can be used to integrate database information into the message +summary. + +* Menu: + +* VM Message Summary:: BBDB information in message summary +* VM what records are displayed:: +* VM automatic setup of vm-set-auto-folder-alist:: +* VM automatic adding of labels:: + + +File: bbdb.info, Node: VM Message Summary, Next: VM what records are displayed, Prev: VM Features, Up: VM Features + +VM Message Summary Enhancements +............................... + +VM users can cause their summary buffer to display the name of the +message sender according to BBDB data, instead of according to the +contents of the current message's headers. In VM 5.40 or later, use +the summary format control `%UB"' instead of `"%F"', and the current +record name will be shown there if available. If no entry is found it +behaves like `"%F"'. See the documentation for `vm-summary-format' for +more details. Warning, this may significantly slow down summary +generation for large folders. + + +File: bbdb.info, Node: VM what records are displayed, Next: VM automatic setup of vm-set-auto-folder-alist, Prev: VM Message Summary, Up: VM Features + +VM configuration of what records the BBDB buffer shows +...................................................... + +Email addresses which match `vm-summary-uninteresting-senders' are +ignored. + + The records in the BBDB buffer are listed in the same order as found. + + +File: bbdb.info, Node: VM automatic setup of vm-set-auto-folder-alist, Next: VM automatic adding of labels, Prev: VM what records are displayed, Up: VM Features + +VM automatic setup of `vm-set-auto-folder-alist' +................................................ + +VM users can setup the `vm-set-auto-folder-alist' automatically by +calling `bbdb/vm-set-auto-folder-alist'. This adds for each BBDB +record containing a `bbdb/vm-set-auto-folder-alist-field' an entry to +`vm-set-auto-folder-alist'. + + The record field can contain a string which is used as folder name or +if it starts with a `'' it is treated as lisp expression returning a +folder name. + + +File: bbdb.info, Node: VM automatic adding of labels, Prev: VM automatic setup of vm-set-auto-folder-alist, Up: VM Features + +VM automatic adding of labels +............................. + +`bbdb/vm-auto-add-label-list' is a List used by +`bbdb/vm-auto-add-label' to automatically label messages. Each element +in the list is either a string or a list of two strings. If a single +string then it is used as both the field value to check for and the +label to apply to the message. If a list of two strings, the first is +the field value to search for and the second is the label to apply. + + `bbdb/vm-auto-add-label-field bbdb-define-all-aliases-field' is the +field used by `bbdb/vm-auto-add-label' to automatically label messages. +Value is either a single symbol or a list of symbols of bbdb fields that +`bbdb/vm-auto-add-label' uses to check for labels to apply to messages. +Defaults to `bbdb-define-all-aliases-field' which is typically +`mail-alias'. + + `bbdb/vm-auto-add-label' automatically adds labels to messages based +on the `bbdb/vm-auto-add-label-field bbdb-define-all-aliases-field' +field. Add this to `bbdb-notice-hook' and if using VM each message +that bbdb notices will be checked. If the sender has a value in the +`bbdb/vm-auto-add-label-field' in their BBDB record that matches a +value in `bbdb/vm-auto-add-label-list' then a VM label will be added to +the message. + + This works great when `bbdb-user-mail-names' is set. As a result +mail that you send to people (and copy yourself on) is labeled as well. + + +File: bbdb.info, Node: Other Packages, Next: Options, Prev: Reader-specific Features, Up: Top + +Using the BBDB with other packages +================================== + +The BBDB adds functionality to several packages. The following sections +detail these augmentations. + +* Menu: + +* Using Message Mode:: Using the BBDB with Message Mode +* Using Reportmail:: Using the BBDB with Reportmail +* Using Supercite:: Using the BBDB with Supercite +* Using Web Browsers:: Using the BBDB with Web Browsers + + +File: bbdb.info, Node: Using Message Mode, Next: Using Reportmail, Prev: Other Packages, Up: Other Packages + +Using the BBDB with Message Mode +-------------------------------- + +At this time, the only feature the BBDB adds to Message mode is the +binding to `M-TAB' which allows for BBDB record completion. + + +File: bbdb.info, Node: Using Reportmail, Next: Using Supercite, Prev: Using Message Mode, Up: Other Packages + +Using the BBDB with Reportmail +------------------------------ + +The BBDB can modify the `reportmail.el' package to use information from +BBDB records when identifying the senders or recipients of e-mail +messages. + + In normal operation, Reportmail displays the name and net address +sender and recipient of incoming messages. The BBDB can be configured +to intercept and rewrite this information before it appears in the +Emacs mode-line. It first attempts to rewrite the sender and/or +recipient information by substituting those addresses with information +from the BBDB. Replacement information is first sought from the +`mail-name' field in the respective BBDB records. If no such field is +found, the `name' field is returned. If no BBDB record is found, no +rewriting is performed. + + The BBDB-Reportmail augmentation is accomplished through the +advising of the Reportmail `display-time-get-field' function in order +to do a-posteriori modification of the returned value. The +augmentation uses the `bbdb/reportmail-alternate-full-name' function to +retrieve data from the BBDB for use in rewriting. + + +File: bbdb.info, Node: Using Supercite, Next: Using Web Browsers, Prev: Using Reportmail, Up: Other Packages + +Using the BBDB with Supercite +----------------------------- + +The BBDB can be used with Supercite to store attributions with BBDB +records. Normally, when a non-default attribution is entered for a +given message, the entered attribution is used for that message, and is +then discarded. When the BBDB-Supercite augmentation is enabled, the +non-default attribution will be added to the record (if any) for the +entity being cited. This poor explanation sounds complicated, but it's +not. If a message from `Jamie Zawinski ' is being +replied to, Supercite will, by default, suggest the citation `Jamie'. +If the non-default citation `jwz' is entered, Supercite can save it +with the BBDB record for `Jamie Zawinski' in the `attribution' field. + + The field used can be changed by changing the value of +`bbdb/sc-attribution-field'. + + +File: bbdb.info, Node: Using Web Browsers, Prev: Using Supercite, Up: Other Packages + +Using the BBDB with Web Browsers +-------------------------------- + +The BBDB/Web Browser integration is in two parts, one which is +automatically enabled, and one which must be manually enabled (*note +Web Browser Prep::). The first feature added is the ability to display +the URL associated with a given record in a Web Browser. The second is +the ability to add URLs to BBDB records from within W3, the Emacs Web +Browser. + + Pressing `W' in the `*BBDB*' buffer while the cursor is positioned +over a record with a `www' field will cause the first URL in the field +to be loaded in a Web Browser. This functionality uses `browse-url' to +display URLs - see the documentation for `browse-url' for information on +selecting the browser to be used. + + If W3 is used, and if the BBDB/W3 functionality has been enabled as +described in *Note Web Browser Prep::, pressing the `:' key will add +the URL currently being displayed in W3 to a user-specified BBDB record. + + +File: bbdb.info, Node: Options, Next: Utilities, Prev: Other Packages, Up: Top + +Options +======= + +There are many variables which control the behavior of the Insidious Big +Brother Database, and there are many hook-variables which can be used to +modify its behavior in more complex ways. Several pieces of +functionality are included which use the hooks in this way. + +* Menu: + +* Customization Parameters:: Customization Parameters +* Customization Hooks:: Customization Hooks +* Predefined Hooks:: Predefined Hooks + + +File: bbdb.info, Node: Customization Parameters, Next: Customization Hooks, Prev: Options, Up: Options + +Customization Parameters +------------------------ + +`bbdb-file' + The name of the file which contains your personal database. + Default: `~/.bbdb'. + +`bbdb-default-area-code' + The default area code to use when prompting for a new phone number. + Default: 415. This must be a number, not a string. + +`bbdb-north-american-phone-numbers-p' + Whether syntax-checking of phone numbers should be enforced. + Default: `t'. This only works for Bell-system phone numbers. If + this is true, then you can't enter invalid phone numbers, and all + phone numbers are pretty-printed in the same way. European phone + numbers don't have as strict a syntax, however, so this is a + harder problem for them (on which I am punting). + + You can have both styles of phone number in your database by + providing a prefix argument to the `bbdb-insert-new-field' + command. + +`bbdb-check-zip-codes-p' + Whether syntax-checking of zip codes should be enforced. Default: + `t'. If this is true, you can't enter invalid zip codes. A zip + code is valid if it matches one of the regular expressions in the + variable `bbdb-legal-zip-codes'. + +`bbdb-address-formatting-alist' + Controls the display of addresses in the buffer. Each entry in + this list consists of an identifying function and a formatting + function. The identifying function must accept an address and + return `t' if the associated formatting function is to be used. + The formatting function must insert the formatted address in the + current buffer. Identifying functions usually base their decision + on the zip code format or on the country name. The default + entries will format an address using continental style if the zip + code matches `bbdb-continental-zip-regexp'. If the zip code does + not match, addresses are formatted in US style. + +`bbdb-continental-zip-regexp' + Decides whether an address should be formatted using US or European + style. If the zip code of an address matches the regular + expression, the European style is used. This works only if the + expression `(bbdb-address-is-continental . + bbdb-format-address-continental)' is part of + `bbdb-address-formatting-alist'. + +`bbdb-electric-p' + Whether bbdb mode should be "electric" like `electric-buffer-list'. + Default: `t'. What this means is that the BBDB buffer which pops + up when you use it can be disposed of by pressing the space bar, at + which point your window configuration will be restored to what it + was before you invoked the db list. (The `bbdb-mode' commands + still work as well.) + + There are some problems with electric modes; for example, keyboard + macros and incremental search don't work. (This is not a bug in + BBDB, but in `electric.el'.) + +`bbdb-case-fold-search' + Default: the same as `case-fold-search'. `case-fold-search' is + bound to this by `M-x bbdb' and related commands. This variable + lets the case-sensitivity of `^S' and of the bbdb searching + commands be different. + +`bbdb/mail-auto-create-p' + If this is `t' (the default), then VM, MH, and RMAIL will + automatically create new bbdb records for people you receive mail + from. If this variable is a function name or lambda expression, + then it is called with no arguments to decide whether an entry + should be automatically created. You can use this to, for + example, not create records for messages which have reached you + through a particular mailing list, or to only create records + automatically if the mail has a particular subject. See the + variables `bbdb-ignore-most-messages-alist' and + `bbdb-ignore-some-messages-alist' (*Note Predefined Hooks::.) + +`bbdb/news-auto-create-p' + If this is `t' (default: `nil'), then GNUS will automatically + create new BBDB records for people you read messages by. If this + is a function name or lambda expression, then it is called with no + arguments to decide whether an entry should be automatically + created. You can use this to, for example, create or not create + messages which have a particular subject. See the variable + `bbdb-auto-notes-alist' (*Note Predefined Hooks::.). + + If you want to autocreate messages based on the current newsgroup, + it's probably a better idea to set this variable to `t' or `nil' + from your `gnus-select-group-hook' instead. + + To automatically remember users in certain groups, you can do + something like + (setq gnus-select-group-hook + '(lambda () + (setq bbdb/news-auto-create-p + (or (string= "some.news.group" gnus-newsgroup-name) + (string= "other.news.group" gnus-newsgroup-name))))) + + +`bbdb-quiet-about-name-mismatches' + If this is false (the default), then BBDB will prompt you when it + notices a name change, that is, when the "real name" in a message + doesn't correspond to a record already in the database with the + same network address. As in, "John Smith " versus + "John Q. Smith ". If this is true, then you will + not be asked if you want to change it (and it will not be changed.) + If a number then it is the number of seconds to sit-for while + displaying the name mismatch. + +`bbdb-use-alternate-names' + If this is false, then the BBDB will not use the AKA field. + Otherwise (the default) then the mail and news interfaces will ask + you if you want to add an alternate name when a name-change is + noticed, and will ask you whether the new name should be made the + primary one. Note that if `bbdb-quiet-about-name-mismatches' is + true, you will not be asked any questions about alternate names. + +`bbdb-readonly-p' + If this is true (default: `nil'), then nothing will attempt to + change the database implicitly, and you will be prevented from + doing it explicitly. If you have more than one emacs running at + the same time, you might want to arrange for this to be set to `t' + in all but one of them. + +`bbdb-auto-revert-p' + If this variable is true (default: `nil') and the BBDB file is + noticed to have changed on disk, it will be automatically reverted + without prompting you first. Otherwise you will be asked. (But + if the file has changed and you have made changes in memory as + well, you will always be asked.) + +`bbdb-notice-auto-save-file' + If this is true (default: `nil'), then the BBDB will notice when + its auto-save file is newer than the file is was read from, and + will offer to revert. + +`bbdb-use-pop-up' + If true (the default), display a continuously-updating BBDB window + while in VM, MH, RMAIL, or GNUS. Each time a new message is + selected, the record corresponding to that message's sender will + be displayed in another window. The buffer in this other window + will be in bbdb-mode, and all corresponding commands will be + available. + + This buffer will be positioned on the screen by finding the tallest + of the windows present, and splitting it such that the bottom + `bbdb-pop-up-target-lines' lines of the window display the + `*BBDB*' buffer. With the default configurations of VM, MH, + RMAIL, and GNUS, this means that the bbdb-list buffer will be just + below the message-body buffer. + + If this is the symbol `horiz', then the BBDB window will be + stacked horizontally instead of vertically, if there is room to do + that tastefully. + +`bbdb-pop-up-target-lines' + Desired number of lines in a VM/MH/RMAIL/GNUS pop-up BBDB window, + default 5. + +`bbdb-completion-type' + Controls the behavior of the `bbdb-complete-name' command. If + `nil' (the default), completion is done across the set of all + full-names and user-ids in the database; if the symbol `name', + completion is done on real-names only; if the symbol `net', + completion is done on network addresses only; if it is `primary', + then completion is done only across the set of primary network + addresses (the first address in the list of addresses for a given + user). If it is `primary-or-name', completion is done across + primaries and real names. + +`bbdb-expand-mail-aliases' + If non-nil, expand mail aliases in `bbdb-complete-name'. + +`bbdb-complete-name-allow-cycling' + Whether to allow cycling of email addresses when calling + `bbdb-complete-name' on a completed address in a composition + buffer." + +`bbdb-complete-name-full-completion' + Show full expanded completion rather than partial matches. If t + then do it always, if a number then just is the number of + completions for a specific match is below that number. + +`bbdb-user-mail-names' + A regular expression identifying the addresses that belong to you. + If a message from an address matching this is seen, the BBDB + record for the `To:' line will be shown instead of the one for the + `From:' line. If this is `nil', it will default to the value of + `(user-login-name)'. + +`bbdb-always-add-addresses' + If this is `t', then whenever the Insidious Big Brother Database + notices a new email address corresponding to a person who is in the + database, it will add it to the database. If this is `nil' (the + default), then whenever a new network address is noticed for a + person in the database, you will be asked whether to add the + address. If this is the symbol `never' (really if it is not `t' + and not `nil') then new network addresses will never be + automatically added. + +`bbdb-new-nets-always-primary' + If this is `t', then when the Insidious Big Brother Database adds + a new address to a record, it will always add it to the front of + the list of addresses, making it the primary address. If this is + `nil' (the default), then you will be asked. If this is the + symbol `never' (really if it is not `t' and not `nil') then new + network addresses will always be added to the end of the list. + +`bbdb-canonicalize-redundant-nets-p' + If this is non-`nil', redundant network addresses will be ignored. + If a record has an address of the form `foo@baz.com', setting this + to `t' will cause subsequently-noticed addresses like + `foo@bar.baz.com' to be ignored (since we already have a more + general form of that address.) This is similar in function to one + of the possible uses of the variable `bbdb-canonicalize-net-hook' + but is somewhat more automatic. (This can't quite be implemented + in terms of the canonicalize-net-hook because it needs access to + the database to determine whether an address is redundant, and the + canonicalize-net-hook is purely a textual manipulation which is + performed before any database access.) + +`bbdb-message-caching-enabled' + Whether caching of the message->bbdb-record association should be + used for the interfaces which support it (VM, MH, and RMAIL). + This can speed things up a lot. One implication of this variable + being true (the default) is that the `bbdb-notice-hook' will not + be called each time a message is selected, but only the first + time. Likewise, if selecting a message would generate a question + (whether to add an address, change the name, etc) you will only be + asked that question the very first time the message is selected. + +`bbdb-offer-save' + If `t' (the default), then certain actions will cause the BBDB to + ask you whether you wish to save the database. If `nil', then the + offer to save will never be made. If not `t' and not `nil', then + any time it would ask you, it will just save it without asking. + + + +File: bbdb.info, Node: Customization Hooks, Next: Predefined Hooks, Prev: Customization Parameters, Up: Options + +Customization Hooks +------------------- + +All of the hooks variables described below may be set to a symbol or +lambda expression, which will be funcalled; or may be set to a list of +symbols or lambda expressions, each of which will be funcalled in turn. +Almost all hooks in Emacs work this way. But notice that some of the +hooks described below are called with arguments. + +`bbdb-list-hook' + Hook or hooks invoked after the bbdb-list-buffer is filled in. + Invoked with no arguments. + +`bbdb-create-hook' + Hook or hooks invoked each time a new bbdb-record is created. + Invoked with one argument, the new record. This is called + _before_ the record is added to the database. Note that + `bbdb-change-hook' will be called as well. + +`bbdb-change-hook' + Hook or hooks invoked each time a bbdb-record is altered. Invoked + with one argument, the record. This is called _before_ the + database buffer is modified. Note that if a new bbdb record is + created, both this hook and `bbdb-create-hook' will be called. + +`bbdb-mode-hook' + Hook or hooks invoked when the `*BBDB*' buffer is created. + +`bbdb-notice-hook' + Hook or hooks invoked each time a bbdb-record is "noticed," that + is, each time it is displayed by the news or mail interfaces. + Invoked with one argument, the new record. The record need not + have been modified for this to be called - use `bbdb-change-hook' + for that. You can use this to, for example, add something to the + notes field based on the subject of the current message. It is up + to your hook to determine whether it is running in GNUS, VM, MH, + or RMAIL, and to act appropriately. + + Also note that `bbdb-change-hook' will _not_ be called as a result + of any modifications you may make to the record inside this hook. + + Beware that if the variable `bbdb-message-caching-enabled' is true + (a good idea) then when you are using VM, MH, or RMAIL, this hook + will be called only the first time that message is selected. (The + GNUS interface does not use caching.) When debugging the value of + this hook, it is a good idea to set caching-enabled to `nil'. + +`bbdb-after-read-db-hook' + Hook or hooks invoked (with no arguments) just after the Insidious + Big Brother Database is read in. Note that this can be called + more than once if the BBDB is reverted. One possible use for this + is to rename the `.bbdb' buffer; for example + + `(setq bbdb-after-read-db-hook '(lambda () (rename-buffer " + bbdb")))' + + will cause the buffer visiting the `bbdb-file' to be called + `" bbdb"'. The leading space in its name will prevent it from + showing up in the buffer list. + +`bbdb-load-hook' + Hook or hooks invoked (with no arguments) when the Insidious Big + Brother Database code is first loaded. WARNING: Slow functions + should not be put on this hook, as the BBDB code will, if not + loaded before, be loaded during the first use of BBDB-related + Customization functions. Slow functions should be put on + `bbdb-initialize-hook'. + +`bbdb-initialize-hook' + Hook or hooks invoked (with no arguments) when the + `bbdb-initialize' function is called. + +`bbdb-canonicalize-net-hook' + If this is non-`nil', it should be a function of one argument: a + network address string. (Note that, unlike the other + hook-variables described above, this may not be a list of + functions.) Whenever the Insidious Big Brother Database "notices" + a message, the corresponding network address will be passed to + this function first, as a kind of "filter" to do whatever + transformations upon it you like before it is compared against or + added to the database. For example: it is the case that + `CS.CMU.EDU' is a valid return address for all mail originating at + a machine in the `.CS.CMU.EDU' domain. So, if you wanted all such + addresses to be canonically hashed as `user@CS.CMU.EDU', instead + of as `user@somehost.CS.CMU.EDU', you might set this variable to a + function like this: + + (setq bbdb-canonicalize-net-hook + '(lambda (addr) + (cond ((string-match + "\\`\\([^@]+@\\).*\\.\\(CS\\.CMU\\.EDU\\)\\'" + addr) + (concat (substring addr + (match-beginning 1) (match-end 1)) + (substring addr + (match-beginning 2) (match-end 2)))) + (t addr)))) + + You could also use this function to rewrite UUCP-style addresses + into domain-style addresses, or any number of other things. + + This function will be called repeatedly until it returns a value + EQ to the value passed in. So multiple rewrite rules might apply + to a single address. + + There is an example of the use of this variable in the file + `bbdb-hooks.el': the function `sample-bbdb-canonicalize-net-hook'. + + The `bbdb-canonicalize-net-hook' is powerful in that it allows +arbitrary rewriting of addresses, however, in many cases that is +overkill. The function `bbdb-delete-redundant-nets' can be used as a +value of `bbdb-change-hook' to cause network addresses which appear to +be "redundant" to be deleted each time a modification is made to a +record. + + This works as follows: suppose one gets mail from `user@foo.bar.com', +and then later gets mail from `user@bar.com'. At this point, one can +generally delete the `user@foo.bar.com' address, since the +`user@bar.com' address is more general. (See also the variable +`bbdb-canonicalize-redundant-nets-p', which has the effect of ignoring +subsequent addresses from `user@quux.bar.com' if the address +`user@bar.com' is already known.) + + +File: bbdb.info, Node: Predefined Hooks, Prev: Customization Hooks, Up: Options + +Predefined Hooks +---------------- + +If the variable `bbdb-change-hook' is set to the symbol +`bbdb-timestamp-hook' (the default), then every record in the database +will have a field named `timestamp', which will always contain the date +and time at which this record was created or last modified. + + If the variable `bbdb-create-hook' is set to the symbol +`bbdb-creation-date-hook' (the default), then every record in the +database will have a field named `creation-date', which will contain +the date and time at which this record was added to the database. + + If the variable `bbdb/mail-auto-create-p' is set to the symbol +`bbdb-ignore-most-messages-hook', then the variable +`bbdb-ignore-most-messages-alist' will determine which messages should +have records automatically created for them. The format of this alist +is + (( HEADER-NAME . REGEXP ) ... ) + +for example, + (("From" . "@.*\\.maximegalon\\.edu") + ("Subject" . "time travel")) + +will cause BBDB entries to be made only for messages sent by people at +Maximegalon U., or (that's _or_) people posting about time travel. + + There may be only one entry per header in this alist: that is, + + (("From" . "addr1\\|addr2") ... ) + +is legal, but + + (("From" . "addr1") ("From" . "addr2") ... ) + +is not. + + If the variable `bbdb/mail-auto-create-p' is set to the symbol +`bbdb-ignore-some-messages-hook', then the variable +`bbdb-ignore-some-messages-alist' will determine which messages should +have records automatically created for them. This is the exact inverse +of the semantics of the `bbdb-ignore-most-messages-alist': the alist +specifies which messages should _not_ have records automatically +created for them, instead of which should. For example, + + (("From" . "mailer.daemon") + ("To" . "mailing-list-1\\|mailing-list-2") + ("CC" . "mailing-list-1\\|mailing-list-2")) + +will cause BBDB entries to not be made for messages from any mailer +daemon, or messages sent to or CCed to either of two mailing lists. + + The variable `bbdb/news-auto-create-p' may be set to either of the +above-mentioned functions as well, to get this behavior for netnews +messages instead of mail messages. + + If the variable `bbdb-notice-hook' is set to the symbol +`bbdb-auto-notes-hook', then the variable `bbdb-auto-notes-alist' may +be used to automatically add text to the notes fields of the records +corresponding to certain messages. The format of this alist is + + (( HEADER-NAME + (REGEXP . STRING) ... ) + ... ) + +for example, + + (("To" ("-vm@" . "VM mailing list")) + ("Subject" ("sprocket" . "mail about sprockets") + ("you bonehead" . "called me a bonehead"))) + +will cause the text `"VM mailing list"' to be added to the notes field +of the record corresponding to anyone you get mail from via one of the +VM mailing lists. If, that is, `bbdb/mail-auto-create-p' is set such +that the record would have been created, or if the record already +existed. + + The format of elements of this list may also be + + (REGEXP FIELD-NAME STRING) + +or + (REGEXP FIELD-NAME STRING REPLACE-P) + +meaning add the given string to the named field. The field-name may not +be `name', `aka', `address', `phone', or `net' (builtin fields) but +must be either `notes', `company', or the name of a user-defined +note-field. + + ("pattern" . "string to add") + +is equivalent to + + ("pattern" notes "string to add") + +STRING can contain `\&' or `\N' escapes like in the function +`replace-match'. For example, to automatically add the contents of the +organization field of a message to the `company' field of a BBDB +record, you can use this: + + ("Organization" (".*" company "\\&")) + +(Note you need two \ to get a single \ into a lisp string literal.) + + If STRING is an integer N, the Nth matching subexpression is used, +so the above example could be written more efficiently as + + ("Organization" (".*" company 0)) + + If STRING is neither a string or an integer, it should be a function +which is called with the contents of the field, and the result of the +function call is used. + + If the REPLACE-P flag is true, then the string replaces the old +contents instead of being appended to it. + + If multiple clauses match the message, all of the corresponding +strings will be added. + + If the string is being appended (REPLACE-P is false or not provided) +then the new string is appended to the end of the existing field value, +with an intervening newline. So each piece of text automatically added +to this field will go on its own line. + + You can control what the separator is by putting a `field-separator' +property on the symbol naming the field. For example, to make text +automatically added to a field named `newsgroups' be separated by +commas, you could do + + (put 'newsgroups 'field-separator "; ") + + This variable works for news as well. You might want to arrange for +this to have a different value when in mail as when in news. + + There may be only one entry per header in this alist: that is, + + (("Subject" ("\\bfoo\\b" . "Foo!!") + ("bar" . "Bar!"))) + +will work, but + + (("Subject" ("\\bfoo\\b" . "Foo!!")) + ("Subject" ("bar" . "Bar!"))) + +will not. + + Here's a more complicated example: some people include bitmaps of +themselves in their mail messages in an X-Face: header field. You can +capture this field into the `*BBDB*' with the following: + + (setq bbdb-auto-notes-alist + (append bbdb-auto-notes-alist + (list "x-face" + (list (concat "[ \t\n]*\\([^ \t\n]*\\)" + "\\([ \t\n]+\\([^ \t\n]+\\)\\)?" + "\\([ \t\n]+\\([^ \t\n]+\\)\\)?" + "\\([ \t\n]+\\([^ \t\n]+\\)\\)?" + ) + 'face + "\\1\\3\\5\\7")))) + +(The calls to `list' and `concat' are just for readability, it could +easily be a constant.) The tricky bit here is that it strips out the +newlines and whitespace used for header continuation, which are not +actually a part of the face data. So though the mail message may have +the face data on multiple lines, the entry in the `*BBDB*' will be just +one line. + + `bbdb-auto-notes-ignore' is an alist of headers and regexps to +ignore in `bbdb-auto-notes-hook'. Each element looks like + + (HEADER . REGEXP) + +for example, + + ("Organization" . "^Gatewayed from\\|^Source only") + +would exclude the phony `Organization:' headers in GNU mailing-lists +gatewayed to the `gnu.*' newsgroups. Note that this exclusion applies +only to a single field, not to the entire message. For that, use the +variable `bbdb-auto-notes-ignore-all'. + + `bbdb-auto-notes-ignore-all' is an alist of headers and regexps +which cause the entire message to be ignored in `bbdb-auto-notes-hook'. +Each element looks like + + (HEADER . REGEXP) + +for example, + + ("From" . "BLAT\\.COM") + +would exclude any notes recording for message coming from `BLAT.COM'. +Note that this is different from `bbdb-auto-notes-ignore', which +applies only to a particular header field, rather than the entire +message. + + +File: bbdb.info, Node: Utilities, Next: Internals, Prev: Options, Up: Top + +Utilities +========= + +This section describes BBDB functionality that does not fit neatly into +other sections. + +* Menu: + +* bbdb-ftp:: Storing FTP sites in the BBDB +* bbdb-print:: Print the BBDB +* bbdb-snarf:: Record generation from raw text +* bbdb-srv:: External control of the BBDB + + +File: bbdb.info, Node: bbdb-ftp, Next: bbdb-print, Up: Utilities + +`bbdb-ftp' +---------- + +The `bbdb-ftp' utility enables the storage of FTP sites as BBDB +records. The `bbdb-create-ftp-site' function is used to create a BBDB +record for an FTP site. The command will prompt for information needed +to create the record. The FTP site for a given record can be accessed +with the `bbdb-ftp' command. + + +File: bbdb.info, Node: bbdb-print, Next: bbdb-snarf, Prev: bbdb-ftp, Up: Utilities + +`bbdb-print' +------------ + +`bbdb-print' is a utility for pretty-printing entries from the BBDB +using TeX. It is invoked by pressing `P' in the `*BBDB*' buffer - this +will cause all records in the BBDB to be printed as governed by the +variables described below. If `P' is prefixed by a `*', only the +currently-displayed records will be printed. Once invoked, `bbdb-print' +will generate the TeX output in a buffer named `~/bbdb.tex' (controlled +by `bbdb-print-file-name'). The generated output will be shown, and +must be manually saved. + + For each record printed, `bbdb-print' will look for the presence of +the `tex-name' field. If this field is found, its value will be printed +instead of the `name' field for the record in question. This field is +intended to allow the storage of names with accents or other characters +that would be illegal in the address portion of a message. While other +fields have special characters quoted by `bbdb-print' as described +below, the contents of the `tex-name' field (if present) are used +verbatim. + + The following variables govern the printing of records (and of the +printing of the fields therein): + +`bbdb-print-omit-fields' + This variable should be set to a list of the fields that are not + to be printed by `bbdb-print'. It defaults to: + `(omit tex-name aka mail-alias)' + +`bbdb-print-file-name' + The name of the file where generated TeX output is to be stored. + The default is `~/bbdb.tex'. + +`bbdb-print-require' + The fields required for printing a record. This allows, for + example, only records with phone numbers to be printed. The value + of the value of the variable will be evaluated once for each + record, and the record will be printed only if the evaluation + returns a non-nil value. The symbols `name', `company', `net', + `phone', `address', and `notes' will be set to the appropriate + values during evaluation; they will be nil if the field does not + exist or is elided. + + The value of this variable can be any lisp expression, but + typically it will be used for a boolean combination of the field + variables, as in the following simple examples: + + * Print only people whose phone numbers are known: + `(setq bbdb-print-require 'phone)' + + * Print people whose names AND companies are known: + `(setq bbdb-print-require '(and name company))' + + * Print people whose names, and either addresses OR phone + numbers are known: + `(setq bbdb-print-require '(and name (or address phone))).' + The default value is: + `(or address phone)' + +`bbdb-print-alist' + Formatting options for all formats of `bbdb-print'. The value is + an alist of the form + `((OPTION . VALUE) (OPTION . VALUE) ...)' + Separate settings can be + configured using `bbdb-print-brief-alist' and + `bbdb-print-full-alist'. Settings in these variables will + override the ones in `bbdb-print-alist'. + + The possible options and legal settings are: + `columns' + `1', `2', `3', `4', `quad' (4 little 2-column pages per + sheet) or `grid' (12 credit-card-sized pages per sheet). + + `separator' + `0'-`7', the style of heading for each letter. `0'=none, + `1'=line, `2'=boxed letters, `3'=large boxed letters, + `4'=large letters, `5'=letters with lines, `6'=letters with + suits, `7'=boxed letters with suits. + + `omit-area-code' + A regular expression matching area codes to omit. + + `phone-on-first-line' + If `t', the first phone number will be put on the same line + as the name. If `nil', the name will be the only text on the + line. If set to a string, the field of type `phone' whose + name matches the string will be used. The string should be a + valid regular expression. + + `n-phones' + Maximum number of phone numbers to include. + + `n-addresses' + Maximum number of addresses to include. + + `include-files' + List of TeX files to `\input'. If the filenames are not + absolute, the files must be located somewhere in the TeX + input path. + + `ps-fonts' + Postscript fonts (TimesNewRoman and Courier) will be used if + the value is non-`nil'. Standard TeX fonts (ec-fonts) will + be used otherwise. + + `font-size' + The integer point size of the font to be used. + + `hsize' + The horizontal dimension of the pages. The value must be a + string, and must be a valid TeX dimension. Alternatively, + the TeX default will be used if the value is `nil'. + + `vsize' + The vertical dimension of the pages. The value must be a + string, and must be a valid TeX dimension. Alternatively, + the TeX default will be used if the value is `nil'. + + `hoffset' + The TeX output will be offset to the right by the value of + this option. The value must be either a string containing a + valid TeX dimension or `nil' or `0' to use the default TeX + horizontal offset. + + `voffset' + The TeX output will be offset downward by the value of this + option. The value must be either a string containing a valid + TeX dimension or `nil' or `0' to use the default TeX vertical + offset. + + `quad-hsize' + Horizontal size to be used for the individual pages in the + quad format. The value must be a string containing a valid + TeX dimension. + + `quad-vsize' + Vertical size to be used for the individual pages in the quad + format. The value must be a string containing a valid TeX + dimension. + + The default value is + ((omit-area-code . "(AREA-CODE)") + (phone-on-first-line . "^[ \t]*$") + (ps-fonts . nil) + (font-size . 6) + (quad-hsize . "3.15in") + (quad-vsize . "4.5in")) + + Where AREA-CODE is the value of `bbdb-default-area-code' or `000' + if there is no default area code. + +`bbdb-print-brief-alist' + Extra options for the `bbdb-print' brief format. The value(s) of + this variable can either supplement or override the values in + `bbdb-print-alist'. The format and possible values of this + variable are as in `bbdb-print-alist', described above. + + The default value is + ((columns . 1) + (separator . 1) + (n-phones . 2) + (n-addresses . 1) + (include-files "bbdb-print-brief" "bbdb-cols")) + +`bbdb-print-full-alist' + Extra options for the `bbdb-print' non-brief format. The value(s) + of this variable can either supplement or override the values in + `bbdb-print-alist'. The format and possible values of this + variable are as in `bbdb-print-alist', described above. + + The default value is + ((columns . 3) + (separator . 2) + (include-files "bbdb-print" "bbdb-cols")) + +`bbdb-print-prolog' + TeX statements to include at the beginning of the `bbdb-print' + output file. + +`bbdb-print-epilog' + TeX statements to include at the end of the `bbdb-print' output + file. + + + +File: bbdb.info, Node: bbdb-snarf, Next: bbdb-srv, Prev: bbdb-print, Up: Utilities + +`bbdb-snarf' +------------ + +`bbdb-snarf' provides the ability to generate BBDB records from raw +text. If invoked as `bbdb-snarf', it attempts to generate the record +from the information around point (the cursor). If invoked as +`bbdb-snarf-region'(1), the active region is used to generate the +record. + +Restrictions: + + 1. `bbdb-snarf' currently recognizes only US-style phone numbers. + + 2. `bbdb-snarf' works best with things that look like mailing + addresses. + +Example of an address that `bbdb-snarf' will recognize: + + another test person + 1234 Gridley St. + Los Angeles, CA 91342 + 555-1212 + test@person.net + http://www.foo.bar/ + other stuff about this person + + ---------- Footnotes ---------- + + (1) `bbdb-snarf' is actually a wrapper for `bbdb-snarf-region' that +determines the relevant region and passes it on. + + +File: bbdb.info, Node: bbdb-srv, Prev: bbdb-snarf, Up: Utilities + +`bbdb-srv' +---------- + +`bbdb-srv' provides the ability to initiate the display of BBDB records +from outside of Emacs. This allows external programs to cause the BBDB +record for a given person to appear in the running Emacs when, for +example, mail is recieved from that person. One specific application, +described below, is the integration of Netscape and the BBDB, allowing +the display of BBDB records corresponding to Mail and/or News messages +displayed in Netscape. + + `bbdb-srv' is composed of two parts - an external Perl script +(`utils/bbdb-srv.pl'), and an Emacs Lisp file (`lisp/bbdb-srv.el'). +The external portion is used to send commands to the internal portion. + + NOTE: `bbdb-srv' requires `gnuserv' and `itimer', both included with +XEmacs. `gnuserv' must be started with the `gnuserv-start' command +before `bbdb-srv' can be used. + + In it's most basic form, mail or news headers are passed to the Perl +script. The Perl script then causes the BBDB record (if any) +corresponding to the passed headers to be displayed in the running +Emacs. While `bbdb-srv' will operate with just a `From:' field, it +works better when passed both `From:' and `To:' headers. When +`bbdb-srv' notices that the logged-in user is named in the `From:' +header, it will attempt to display the record (if any) for the person +named in the `To:' header. If no `To:' header is passed, it falls back +on the record (if any) for the logged-in user (the person named in the +`From:' header). + + An example manual invocation of `bbdb-srv' is as follows: + + % cat |bbdb-srv.pl + From: Jamie Zawinski + To: Matt Simmons + + + If the invoking user is Jamie Zawinski, the record for Matt Simmons +(if any) will be displayed. If the invoking user is not Jamie +Zawinski, the record for Jamie Zawinski (if any) will be displayed. + + As mentioned above `bbdb-srv' can be used with Netscape Mail and +Netscape News. Please note that it can only be used with the UNIX +versions 3.0b2 and greater of these applications. To allow Netscape to +use `bbdb-srv', set the `NS_MSG_DISPLAY_HOOK' variable to +`bbdb-srv.pl'(1) as follows: + +Bourne Shell (`/bin/sh') and variants: + # NS_MSG_DISPLAY_HOOK bbdb-srv.pl + # export NS_MSG_DISPLAY_HOOK + +C-Shell (`/bin/csh') and variants: + % setenv NS_MSG_DISPLAY_HOOK bbdb-srv.pl + + The following variables can be used to customize the behavior of +`bbdb-srv': + +`bbdb/srv-auto-create-p' + This variable is similar to `bbdb/news-auto-create-p' and + `bbdb/mail-auto-create-p'. That is, when headers are passed in to + `bbdb-srv', a new BBDB record can be created if none exists, + depending on the value of this variable. Possible values are: + `t' + Automatically create new BBDB records if the headers passed + in do not correspond to an already-existing record. + + `nil' + Do not automatically create new BBDB records. + + FUNCTION + FUNCTION is called. If it returns `t', a record will be + created for the person named in the `From:' header. If it + returns `nil', no record will be created. + + A suggested function for use is + `bbdb/srv-auto-create-mail-news-dispatcher'. This function + will attempt to determine the source of the passed headers - + whether they were part of a mail message or of a news + article. The action (if any) dictated by the value of either + `bbdb/mail-auto-create-p' or `bbdb/news-auto-create-p', based + on the determined source of the passed headers. + + +`bbdb/srv/display-delay' + `bbdb-srv' pauses between displaying the records corresponding to + each passed set of headers. This variable controls the length of + time (in seconds) of the delay between the display of different + records. Note when setting this variable that only one set of + headers can be queued at a time. If three sets of headers are + passed to `bbdb-srv' in less than the delay time, only the first + and last will be displayed. + + ---------- Footnotes ---------- + + (1) Use the full path to `bbdb-srv.pl' if it is not in the default +path. + + +File: bbdb.info, Node: Internals, Next: Mailing Lists, Prev: Utilities, Up: Top + +Internals +========= + +This section is currently a dumping ground for things that should +eventually go here, but were found elsewhere in the file. + + INFORMATION IN THIS SECTION IS FOR INFORMATIONAL PURPOSES ONLY. IT +SHOULD NOT BE TAKEN AS DOCUMENTATION OF AN EXTERNAL API. EVERYTHING +LISTED BELOW IS SUBJECT TO CHANGE WITHOUT NOTICE + + The first time you use one of the BBDB commands, this file is read +into an emacs buffer, and remains there. As you make changes to the +database, this buffer is changed as well, ensuring that if it is +auto-saved, it will be saved in its most current state. + +BBDB data file format +--------------------- + +The data file is arranged in a hierarchical fashion. At the top level +are vectors, with one vector per database record. It is very important +that each vector be on its own line, as the BBDB builds and stores +markers based on this layout. The markers are then used to increase +the speed of database modifications (more on this later). The record +vectors contain the individual fields of the record. These fields can +be of any type, but are currently integers, strings, lists of strings, +alists, vectors, or lists of vectors. In the case of fields that +contain one or more vectors, they can be further broken down in terms +of the fields of their component vectors. + + In an effort to provide a more concrete example to illustrate the +above, and to provide a reference for database accessor and modifier +functions, we describe the database format below. This description +starts with the fields of the individual record vectors, and drills +down through the vectors used by some of the fields. + +Record Vectors +.............. + +Name Type Accessor and Modifier Description +First String `bbdb-record-firstname' Entity's first name +name `bbdb-record-set-firstname' +Last name String `bbdb-record-lastname' Entity's last name + `bbdb-record-set-lastname' +AKAs List of `bbdb-record-aka' Alternate names for + Strings `bbdb-record-set-aka' entity +Company String `bbdb-record-company' Company with which + `bbdb-record-set-company' entity is associated +Phones List of `bbdb-record-phones' List of phone number + Vectors `bbdb-record-set-phones' vectors +Addresses List of `bbdb-record-addresses' List of address vectors + Vectors `bbdb-record-set-addresses' +Net List of `bbdb-record-net' List of network +address Strings `bbdb-record-set-net' addresses +Notes String or `bbdb-record-raw-notes' String or Association + Alist `bbdb-record-set-raw-notes'list of note fields + (strings) +Cache Vector `bbdb-record-cache' Record cache. + `bbdb-record-set-cache' Internal version only. + + The phone, address and cache vector fields are described below. +Please note that, as indicated in the table above, the cache is present +only in the internal version of the database - it is not written out as +part of the `.bbdb' file. + + In addition, the accessor and modifier functions for the notes alist +are described. + +Phone Vectors +............. + +To access the fields in the below table, you must first get the list of +phone vectors using the `bbdb-record-phones' function. Note that if +you alter the phones field with the `bbdb-record-set-phones' function, +you are altering the entire phones list for the given record. Use the +modifier functions below for modifications to individual phone vectors. + +Name Type Accessor and Modifier Description +Location String `bbdb-phone-location' Phone number identifier + `bbdb-phone-set-location' +Area Integer `bbdb-phone-area' Area code for phone + `bbdb-phone-set-area' number +Exchange Integer `bbdb-phone-exchange' Exchange (aka prefix) + `bbdb-phone-set-exchange' for phone number +Suffix Integer `bbdb-phone-suffix' Suffix for phone number + `bbdb-phone-set-suffix' +Extension Integer `bbdb-phone-extension' Phone number extension + `bbdb-phone-set-extension' (`0' if none) + +Address Vectors +............... + +To access the fields in the below table, you must first get the list of +address vectors using the `bbdb-record-addresses' function. Note that +if you alter the addresses field with the `bbdb-record-set-addresses' +function, you are altering the entire addresses list for the given +record. Use the modifier functions below for modifications to +individual address vectors. + +Name Type Accessor and Modifier Description +Location String `bbdb-address-location' Address identifier + `bbdb-address-set-location' +Streets List `bbdb-address-streets' List of street address + `bbdb-address-set-streets' lines. `nil' if none. +Street3 String `bbdb-address-street3' Third line of street + `bbdb-address-set-street3' address. "" if none. +City String `bbdb-address-city' City name + `bbdb-address-set-city' +State String `bbdb-address-state' State abbreviation + `bbdb-address-set-state' +Zip Integer `bbdb-address-zip' Zip code + (american) `bbdb-address-set-zip' + List + (non-american) +Country String `bbdb-address-country' Country + `bbdb-address-set-country' + +Cache Vector +............ + +This vector is present only in the internal database representation. It +is not written out to the database file because it contains information +aggregated from the rest of the record that is reconstructed when the +database is read. To write the cache information to the database file +would increase the risk of database inconsistency, and would violate the +principles of normalization. + + To access the cache fields using the functions listed below that +begin with `bbdb-cache-', you must first get the cache vector using the +`bbdb-record-cache' function. The functions that begin with +`bbdb-record-' get the cache vector internally. Note that if you alter +the cache field in the high-level record with the +`bbdb-record-set-cache' function, you are altering the entire cache +vector for the given record. Use the modifier functions below for +modifications to individual cache fields. + +Name Type Accessor and Modifier Description +Name Cache String `bbdb-cache-namecache' Preconcatenated name + `bbdb-cache-set-namecache' of entity +Sort Key String `bbdb-cache-sortkey' Preconcatenated sort + `bbdb-cache-set-sortkey' key for record +Marker Marker `bbdb-cache-marker' Marker in `.bbdb' for + `bbdb-record-marker' start of record + `bbdb-cache-set-marker' + `bbdb-record-set-marker' +Deleted Boolean `bbdb-cache-deleted-p' Set to `t' if record + `bbdb-record-deleted-p' has been deleted, + `bbdb-cache-set-deleted-p' `nil' if not + `bbdb-record-set-deleted-p' + + The functions listed above will return `nil' if their respective +cache fields are not set. The functions listed below will return the +value of their cache fields if set, but will also build (and set) the +correct field values if the fields are unset: + +`bbdb-record-name' + Return the name in the Name Cache field of the cache (if set). If + the name has not been built yet (if the field is `nil'), the name + is built, stored in the Name Cache field, and returned. + +`bbdb-record-sortkey' + Return the name it the Sort Key field of the cache (if set). If + the Sort Key field has not yet been set (if the field is `nil'), + the Sort Key is built, stored in the Sort Key field, and returned. + + +Notes String or Alist +..................... + +If there is only a single note for a given record, the notes field for +that record will be a string. If there is more than one note, the notes +field will be an association list (alist) with elements of the form + + ( NAME . VALUE ) + +where NAME is the symbol for the name of the note, and VALUE is the +value of the note. + +Example BBDB record +................... + + +File: bbdb.info, Node: Mailing Lists, Next: Changes, Prev: Internals, Up: Top + +Mailing Lists +============= + +(If you are looking for a way to create mailing lists with BBDB, you +should be looking at the section on *Note Mail Sending Interfaces::.) + + There are three mailing lists for the BBDB. +`bbdb-info@lists.sourceforge.net' gets moderate traffic, and is +intended for the discussion and distribution of development versions of +the BBDB. Users of development versions of the BBDB should be +subscribed to this list. It is also to this list that bugs should be +reported. *Note Known Bugs::. for instructions on submitting bug +reports. + + The second mailing list `bbdb-announce@lists.sourceforge.net' has +very low volume. Any user of the BBDB should consider subscribing to +this list, as new releases and security issues will be posted here. + + A third mailing list, `bbdb-cvs@lists.sourceforge.net', is intended +for developers to follow the changes made to the BBDB development +version. Developers of the BBDB should consider to subscribe to this +list. + + +File: bbdb.info, Node: Changes, Next: The Latest Version, Prev: Mailing Lists, Up: Top + +Changes in this Version +======================= + +* Menu: + +* Major Changes:: Major changes in this version +* Other Changes:: Not-so-major changes + + +File: bbdb.info, Node: Major Changes, Next: Other Changes, Prev: Changes, Up: Changes + +Major Changes +------------- + +Database File Version Change +............................ + +(the following version-migration text will move in a future version. +It is in this section currently because new users will likely not +experience it) + + There has been a version change in the BBDB database file. The new +version supports non-US zip codes, and an additional "Country" field in +addresses. + + An automatic version-migration mechanism has been implemented that +allows older version `.bbdb' files to either be migrated to the new +version, or used as-is without migrating. When the BBDB detects a +database file with an old version, it will display the features that +have been introduced in the database file from the time of the older +version's implementation. It will offer the choice of migration or use +of the BBDB with the older-version file. + + If migration is chosen, the database file will be automatically +changed to the new format. If migration is declined, the file will +kept in the older format in the `.bbdb' buffer, but will be stored +internally in the new format. When changes need to be made to the +`.bbdb' buffer, changed records will be reverse-migrated from their +internal version to that of the disk file. + + +File: bbdb.info, Node: Other Changes, Prev: Major Changes, Up: Changes + +Other Changes +------------- + +TeX Output +.......... + +By default, ec fonts are used for TeX output instead of cm fonts. With +the `ps-fonts' option set in `bbdb-print-alist', TimesNewRoman and +Courier fonts are used. + + + +File: bbdb.info, Node: The Latest Version, Next: The Future, Prev: Changes, Up: Top + +The Latest Version +================== + +Released versions of the BBDB can be found at the following site: + + * WWW: `http://bbdb.sourceforge.net' + + * FTP: `ftp://ftp.sourceforge.net/pub/bbdb' + +Development versions of the BBDB can be obtained in the following ways: + + * WWW: `http://bbdb.sourceforge.net' + + * Anonymous CVS: See `http://bbdb.sourceforge.net' for instructions. + + Users of development versions of the BBDB should subscribe to the +`bbdb-info' mailing list. *Note Mailing Lists::. + + +File: bbdb.info, Node: The Future, Prev: The Latest Version, Up: Top + +The Future +========== + +The future consists of Bugs and Features. + +* Menu: + +* Known Bugs:: Known Bugs, and how to submit new ones +* TODO List:: The TODO List +* EOL Statements:: EOL (End Of Life) Statements + + +File: bbdb.info, Node: Known Bugs, Next: TODO List, Prev: The Future, Up: The Future + +Known Bugs +---------- + + 1. `M-TAB' conflicts with ispell. Workaround: The binding installed + by the BBDB for address completion/expansion conflicts with that + used by ispell. The suggested workarounds are to rebind the ispell + key (the BBDB binding is not configurable at this time), to + manually invoke ispell via `M-x', or to not use ispell completion + functionality in BBDB-enabled message composition buffers. The + following is an example of such a rebinding, supplied by Kai + Großjohan: + + (defun my-message-mode-keys () + (define-key message-mode-map (kbd "M-TAB") 'bbdb-complete-name)) + (add-hook 'message-mode-hook 'my-message-mode-keys) + + 2. BBDB and abbrev expansion is inconsistent. Workaround: Currently, + `M-TAB' must be used to expand/complete against BBDB names and net + addresses, and `TAB' must be used to expand abbrevs (the values in + the `mail-alias' field). Unification is planned for a future + version. + + 3. The `*BBDB*' buffer does not always come up when the first article + in a Gnus Summary Buffer is selected. Workaround: Pressing `g' + to reload the article. This will cause the `*BBDB*' buffer to be + displayed. + + 4. Expansion will fail when the name to be expanded is a subset of + the name for another record. For example, if you have entries for + `John' and `Johnathan', you will not be able to expand the name + for `John'. Workaround: Use the net address for the subset name + (`John' in this example). + + + It is commonly known that there are no bugs in the BBDB. Bugs found +in defiance of this rule should be submitted using `M-x +bbdb-submit-bug-report'. These bug reports will bbe sent to the +`bbdb-info' mailing list (*note Mailing Lists::) and are available from +public archives. Other big brothers may be reading your bug reports. + + +File: bbdb.info, Node: TODO List, Next: EOL Statements, Prev: Known Bugs, Up: The Future + +TODO List +--------- + +The Near Future +............... + + * Add bbdb/MUA-delete-sender-record + + * Configurable completion. Should allow user to specify "complete on + names first, then nets", etc. + + * More variables for upgrading. Specifically a variable that lets + users specify extra fields for upgrading (an alist `(a . b)' that + says field `a' should be upgraded the same way as field `b'. + + * Change all functions that switch on MUAs to use compose-mail (ex: + `bbdb-send-mail-internal'). + + * Soren Dayton's method for generically extending the BBDB with + special-purpose fields + + * Sorting records on alternate keys. `bbdb-sort-by' from Boris + Goldowsky. + + * Sorting individual types of fields - Sam Steingold's method. + + * Button 3 menus (Mark Moll and Soren Dayton) + + * Conditionalized erasure of properties when text is pasted into the + BBDB. + + * Should notice when there are `Reply-To:' addresses. + + * Should have a command for merging together two divergent copies of + a `.bbdb' file (in case you read mail on one machine and news on + another, for instance.) + + * The `*BBDB*' buffer should be resized to exactly fit what it's + displaying, even when not in "electric" mode. + + * It should be possible to do completion on last names as well as + first names. + + * The BBDB buffer is left at the top of the stack when GNUS is exited + because GNUS runs its exit-hooks too early. This should be fixed. + + * String area codes (German area codes can begin with zeroes) patch + from `Michael Sperber ' + + * Default country variable, similar to `bbdb-default-area-code'. + + * Make format self-describing in comment + + * ISO-8859-x characters in records for printing. + + * Prefix for `W' (`bbdb-www') command to allow selection of + different addresses. + + * Generalized buttons (via extents) for fields. Example: `(a . b)' + means create button that calls `b' for each entry in the `a' field. + + * Remove support for GNUS. Start with lisp Makefile (remove nntp + and gnus loads). + + * More flexible auto-addition. Conditionalizing of addition + (conditions or supplied function). Prompt if multiple records + that meet criteria exist. + + * Different output formats. See Toby Speight's + `' and Bin Mu's + `<199801221605.KAA23663@DerivaTech.Com>'. + + * Generalized area-code-split program that could split, for example, + based on input copied (or straight fetch of page) from the + Bellcore NANP page. + + * Print multivalue (comma-separated) fields with one value per line + + * Easier BBDB extension. See `' + from Soren Dayton. + + * Take birthdays from the BBDB, add them to calendar. From Boris + Goldowsky. + + * Make mail aliases file for other mailers. From Boris Goldowsky. + + * Various patches from Boris Goldowsky in `bbdb-ext'. + + * Various other patches: + - `bbdb-filters-0.2' + + - `bbdb-frame.el' + + - `bbdb-letter-1.0' + + - `bbdb-plz' + + - `bbdb-query' + + - `country' + + - `country-info' + + Note that these files have not been investigated. They may or may + not be incorporated. + + * Ability to remove all properties from copied strings. + + +Not-So-Near Future +.................. + + * Fix Gnus scoring so it rebuilds when gnus-score disappears + + * Multiline note fields + + * Change key to be some kind of unique number + + * There should be better support for non-American addresses and phone + numbers. This might be Near Future if somebody volunteers to send + me patches. + + * Should reimplement "electric" mode to not be so broken. + + * The `*C-o' keystroke should add a field to all displayed records. + Perhaps `*;' should append some text to an arbitrary field of all + displayed records. + + * Multiple `.bbdb' files with precedence relationships. See Wes + Hardaker's + `' + + * Automatically grab information about a person from their sig. See + Graham Clark's `info-bbdb' post + `<6282.199706161624@havra.dcs.ed.ac.uk>' and Adrian Aichner's + `info-bbdb' post `'. + Would like to have `bbdb-snarf' attack the sig then compare the + snarfed data with the header data. + + +Thoughts +........ + + * Are there enough hooks? + + * The interfaces should share more code. + + * The `bbdb-create-internal' function should be more forgiving. + + * More `*' commands in general, including `*d'. + + +File: bbdb.info, Node: EOL Statements, Prev: TODO List, Up: The Future + +End of Life (EOL) Statements +---------------------------- + +The items in the following list describe items for which support will be +removed in coming versions of the BBDB. The items listed are +guaranteed to be supported and present only until the EOL date. They +may be removed without warning at any time thereafter. + + 1. `advertized-bbdb-delete-current-field-or-record' + Support for this function will be removed for version 2.2. It is + recommended that all code depending on this variable be switched + to use `bbdb-delete-current-field-or-record'. The two functions + have the same calling conventions and effects. This EOL statement + was added for version 2.1. + + 2. Support for the GNUS (not Gnus) newsreader + The GNUS-specific parts of the BBDB will be actively removed for + the 2.2 release. No further maintenance and/or bugfixes are + planned for GNUS code at this time. This EOL statement was added + for version 2.1. + + +File: bbdb.info, Node: Thanks, Up: Top + +Thanks +====== + +Thanks to everyone on the info-bbdb mailing list for many useful +suggestions. This hack would be far less insidious without their input! + +Thanks list for versions after 2.00.06. +--------------------------------------- + +Thanks to Alex Schroeder, Ronan Waide, Thomas DeWeese, Robert Fenk, +Didier Verna, Bill Carpenter. + +Thanks list for versions after 1.51 prior to and including 2.00.06. +------------------------------------------------------------------- + +Thanks to Adrian Aichner, Kees de Bruin, David Carlton, Soren Dayton, +Brian Edmonds, Boris Goldowsky, Seth Golub, John Heidemann, Christopher +Kline, Carsten Leonhardt, Hrvoje Niksic, Jens-Ulrik Hoger Petersen, +Colin Rafferty, Matt Simmons, Sam Steingold, Marco Walther, Christoph +Wedler. + +Thanks list for versions prior to and including 1.51. +----------------------------------------------------- + +And special thanks to Sebastian Kremer, Joe Wells, Todd Kaufmann, Andy +Norman, Ivan Vazquez, Stewart Clamen, Roland McGrath, Dave Brennan, +Kimball Collins, Dirk Grunwald, Philippe Queinnec, Boris Putanec, Dave +Disser, Francois Felix Ingrand, Sean Owens, Guido Bosch, Lance Brown, +Tom Emerson, George Hartzell, Luis Miguel Silveira, Kimmo Suominen, +Derek Upham, David Zuhn, Rod Whitby, Richard Mlynarik. + + Last, but not least, thanks to Jamie Zawinski for writing BBDB in the +first place. + + +File: bbdb.info, Node: _, Up: (dir) + +_ +* + + in.sid.i.ous aj \in-'sid-e-*s\ + [L insidiosus, fr. insidiae ambush, fr. insidere to sit in, sit on, + fr. in- + sedere to sit -- more at SIT] + 1 a : awaiting a chance to entrap TREACHEROUS + b : harmful but enticing SEDUCTIVE + 2 a : having a gradual and cumulative effect SUBTLE + b of a disease + : developing so gradually as to be well established before + becoming apparent + in.sid.i.ous.ly av + in.sid.i.ous.ness n + +* Menu: + +* Top:: + + +File: bbdb.info, Node: Concept Index, Next: Variable Index, Up: Top + +Concept Index +************* + +* Menu: + +* %F: VM Message Summary. +* %UB: VM Message Summary. +* *BBDB* buffer: BBDB Mode. +* Adding new fields: BBDB Mode. +* Adding new records: Manual Record Addition. +* Address completion <1>: Mail Sending Interfaces. +* Address completion: Customization Parameters. +* Address display: Customization Parameters. +* AKA: Customization Parameters. +* Alternate names: Customization Parameters. +* Annotating the sender of the current message: Interfaces. +* Auto-save files: Customization Parameters. +* Automatic display of the corresponding record: Customization Parameters. +* Automatically adding text to records: Predefined Hooks. +* Automatically creating records <1>: Customization Parameters. +* Automatically creating records: Predefined Hooks. +* BBDB Mode: BBDB Mode. +* Browsing the Web page for the current record: BBDB Mode. +* Bug Reports: Known Bugs. +* Builtin field types: Database Fields. +* Changing fields: BBDB Mode. +* Changing windows: BBDB Mode. +* Checking zip codes: Customization Parameters. +* Completion: Customization Parameters. +* Continental addresses: Customization Parameters. +* Creating new records <1>: BBDB Mode. +* Creating new records: Manual Record Addition. +* Deleting fields: BBDB Mode. +* Dialling phone numbers: BBDB Mode. +* Display of addresses: Customization Parameters. +* Displaying changed records: BBDB Mode. +* Editing fields: BBDB Mode. +* Electric display: Customization Parameters. +* Elided display: Basic Searching. +* European addresses: Customization Parameters. +* European phone numbers <1>: BBDB Mode. +* European phone numbers: Customization Parameters. +* Finger interface: BBDB Mode. +* Fixing mistakes: BBDB Mode. +* Format of completed address: Mail Sending Interfaces. +* Formatting addresses: Customization Parameters. +* GNUS Subject-buffer: GNUS Subject List. +* Initial Configuration: Initial Configuration. +* Inserting new fields: BBDB Mode. +* Installation: Installation. +* Invalid zip codes: Customization Parameters. +* List of valid zip codes: Customization Parameters. +* Mail address completion <1>: Customization Parameters. +* Mail address completion <2>: Mail Sending Interfaces. +* Mail address completion: Customization Parameters. +* Mail Aliases: Mail Sending Interfaces. +* mail-alias definition: Database Fields. +* mail-alias usage: Mail Sending Interfaces. +* Mailing lists: Mail Sending Interfaces. +* Makefile: Installation. +* mark-char: GNUS Subject List. +* Merging records: BBDB Mode. +* Name completion <1>: Customization Parameters. +* Name completion: Mail Sending Interfaces. +* Normal User Installation: Normal User. +* North American phone numbers <1>: Customization Parameters. +* North American phone numbers: BBDB Mode. +* Not a valid zip code: Customization Parameters. +* One-line display: Basic Searching. +* Phone numbers <1>: Customization Parameters. +* Phone numbers: BBDB Mode. +* Printing records in the database <1>: bbdb-print. +* Printing records in the database <2>: Database Fields. +* Printing records in the database: BBDB Mode. +* Removing fields: BBDB Mode. +* Reordering fields: BBDB Mode. +* Saving your changes: BBDB Mode. +* Searching the database <1>: BBDB Mode. +* Searching the database: Basic Searching. +* Sending mail <1>: Mail Sending Interfaces. +* Sending mail: BBDB Mode. +* Showing the sender of the current message: Interfaces. +* Special Field Names: Database Fields. +* Storing FTP sites in the BBDB: bbdb-ftp. +* Timestamping records: Predefined Hooks. +* Transposing fields: BBDB Mode. +* User-defined fields <1>: Basic Searching. +* User-defined fields: BBDB Mode. +* Valid zip codes: Customization Parameters. +* XEmacs Package Installation: XEmacs Package. +* Zip code checking: Customization Parameters. + + +File: bbdb.info, Node: Variable Index, Prev: Concept Index, Up: Top + +Variable Index +************** + +* Menu: + +* bbdb-address-formatting-alist: Customization Parameters. +* bbdb-after-read-db-hook: Customization Hooks. +* bbdb-always-add-addresses: Customization Parameters. +* bbdb-auto-notes-alist: Predefined Hooks. +* bbdb-auto-notes-ignore: Predefined Hooks. +* bbdb-auto-notes-ignore-all: Predefined Hooks. +* bbdb-auto-revert-p: Customization Parameters. +* bbdb-canonicalize-net-hook: Customization Hooks. +* bbdb-canonicalize-redundant-nets-p: Customization Parameters. +* bbdb-case-fold-search: Customization Parameters. +* bbdb-change-hook: Customization Hooks. +* bbdb-check-zip-codes-p: Customization Parameters. +* bbdb-complete-name-allow-cycling: Customization Parameters. +* bbdb-complete-name-full-completion: Customization Parameters. +* bbdb-completion-display-record: Mail Sending Interfaces. +* bbdb-completion-type: Customization Parameters. +* bbdb-continental-zip-regexp: Customization Parameters. +* bbdb-create-hook: Customization Hooks. +* bbdb-default-area-code: Customization Parameters. +* bbdb-dial-local-prefix: BBDB Mode. +* bbdb-dial-local-prefix-alist: BBDB Mode. +* bbdb-dial-long-distance-prefix: BBDB Mode. +* bbdb-dwim-net-address-allow-redundancy: Mail Sending Interfaces. +* bbdb-electric-p: Customization Parameters. +* bbdb-expand-mail-aliases: Customization Parameters. +* bbdb-file: Customization Parameters. +* bbdb-finger-host-field <1>: Database Fields. +* bbdb-finger-host-field: BBDB Mode. +* bbdb-get-addresses-from-headers: Reader-specific Features. +* bbdb-get-addresses-headers: Reader-specific Features. +* bbdb-get-addresses-to-headers: Reader-specific Features. +* bbdb-get-only-first-address-p: Reader-specific Features. +* bbdb-ignore-most-messages-alist: Predefined Hooks. +* bbdb-ignore-some-messages-alist: Predefined Hooks. +* bbdb-info-file: BBDB Mode. +* bbdb-initialize-hook: Customization Hooks. +* bbdb-legal-zip-codes: Customization Parameters. +* bbdb-list-hook: Customization Hooks. +* bbdb-load-hook: Customization Hooks. +* bbdb-message-caching-enabled: Customization Parameters. +* bbdb-mode-hook: Customization Hooks. +* bbdb-new-nets-always-primary: Customization Parameters. +* bbdb-north-american-phone-numbers-p: Customization Parameters. +* bbdb-notice-auto-save-file: Customization Parameters. +* bbdb-notice-hook <1>: Customization Hooks. +* bbdb-notice-hook: Predefined Hooks. +* bbdb-offer-save: Customization Parameters. +* bbdb-pop-up-target-lines: Customization Parameters. +* bbdb-print-alist: bbdb-print. +* bbdb-print-brief-alist: bbdb-print. +* bbdb-print-epilog: bbdb-print. +* bbdb-print-file-name: bbdb-print. +* bbdb-print-full-alist: bbdb-print. +* bbdb-print-omit-fields: bbdb-print. +* bbdb-print-prolog: bbdb-print. +* bbdb-print-require: bbdb-print. +* bbdb-quiet-about-name-mismatches: Customization Parameters. +* bbdb-readonly-p: Customization Parameters. +* bbdb-send-mail-style: BBDB Mode. +* bbdb-use-alternate-names: Customization Parameters. +* bbdb-use-pop-up: Customization Parameters. +* bbdb-user-mail-names: Customization Parameters. +* bbdb/gnus-header-prefer-real-names: GNUS Subject List. +* bbdb/gnus-header-show-bbdb-names: GNUS Subject List. +* bbdb/gnus-lines-and-from-length: GNUS Subject List. +* bbdb/gnus-mark-known-posters: GNUS Subject List. +* bbdb/gnus-score-default: Gnus Scoring. +* bbdb/gnus-score-field <1>: Gnus Scoring. +* bbdb/gnus-score-field: Database Fields. +* bbdb/mail-auto-create-p <1>: Predefined Hooks. +* bbdb/mail-auto-create-p: Customization Parameters. +* bbdb/news-auto-create-p <1>: Predefined Hooks. +* bbdb/news-auto-create-p: Customization Parameters. +* bbdb/sc-attribution-field: Database Fields. +* bbdb/srv-auto-create-p: bbdb-srv. +* bbdb/srv-display-delay: bbdb-srv. +* bbdb/vm-auto-add-label-field: VM automatic adding of labels. +* bbdb/vm-auto-add-label-list: VM automatic adding of labels. +* bbdb/vm-set-auto-folder-alist-field: VM automatic setup of vm-set-auto-folder-alist. +* gnus-score-find-score-files-function: Gnus Scoring. +* vm-summary-format: VM Message Summary. +* vm-summary-uninteresting-senders: VM what records are displayed. + + + +Tag Table: +Node: Top522 +Node: Installation5043 +Node: General Prerequisites6018 +Ref: General Prerequisites-Footnote-18400 +Node: Normal User8553 +Node: XEmacs Package13936 +Node: Initial Configuration16850 +Ref: Initial Configuration-Footnote-120435 +Ref: Initial Configuration-Footnote-220517 +Ref: Initial Configuration-Footnote-320653 +Node: Gnus Prep20906 +Node: MH-E Prep21623 +Node: RMAIL Prep22212 +Node: Sendmail Prep22812 +Node: VM Prep23277 +Node: Message Prep23888 +Node: Reportmail Prep24464 +Node: Supercite Prep25083 +Node: Web Browser Prep27869 +Node: The BBDB28610 +Node: Database Fields29280 +Node: Basic Searching34972 +Node: Advanced Searching36167 +Node: Manual Record Addition37812 +Node: BBDB Mode38472 +Node: Interfaces51086 +Node: Mail Reading Interfaces52955 +Node: News Reading Interfaces53605 +Node: Mail Sending Interfaces54014 +Node: Reader-specific Features58084 +Node: Gnus Features59429 +Node: Gnus Scoring59987 +Node: Gnus Summary Buffer61239 +Ref: Gnus Summary Buffer-Footnote-165882 +Node: GNUS Subject List66265 +Node: VM Features67935 +Node: VM Message Summary68357 +Node: VM what records are displayed69055 +Node: VM automatic setup of vm-set-auto-folder-alist69474 +Node: VM automatic adding of labels70129 +Node: Other Packages71656 +Node: Using Message Mode72195 +Node: Using Reportmail72506 +Node: Using Supercite73723 +Node: Using Web Browsers74685 +Node: Options75734 +Node: Customization Parameters76253 +Node: Customization Hooks88089 +Node: Predefined Hooks94021 +Node: Utilities101295 +Node: bbdb-ftp101730 +Node: bbdb-print102132 +Node: bbdb-snarf109497 +Ref: bbdb-snarf-Footnote-1110318 +Node: bbdb-srv110439 +Ref: bbdb-srv-Footnote-1114615 +Node: Internals114692 +Node: Mailing Lists123605 +Node: Changes124668 +Node: Major Changes124938 +Node: Other Changes126263 +Node: The Latest Version126556 +Node: The Future127149 +Node: Known Bugs127454 +Node: TODO List129430 +Node: EOL Statements134142 +Node: Thanks135187 +Node: _136590 +Node: Concept Index137181 +Node: Variable Index142436 + +End Tag Table diff --git a/xemacs-packages/info/ediff.info b/xemacs-packages/info/ediff.info new file mode 100644 index 00000000..4dd5dd6a --- /dev/null +++ b/xemacs-packages/info/ediff.info @@ -0,0 +1,2668 @@ +This is ediff.info, produced by makeinfo version 4.7 from ediff.texi. + + This file documents Ediff, a comprehensive visual interface to Unix +diff and patch utilities. + + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +2003, 2004, 2005, 2006 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +INFO-DIR-SECTION Editors +START-INFO-DIR-ENTRY +* Ediff: (ediff). A visual interface for comparing and merging programs. +END-INFO-DIR-ENTRY + + +File: ediff.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: About Ediff. +* Major Entry Points:: How to use Ediff. +* Session Commands:: Ediff commands used within a session. +* Registry of Ediff Sessions:: Keeping track of multiple Ediff sessions. +* Session Groups:: Comparing and merging directories. +* Remote and Compressed Files:: You may want to know about this. +* Customization:: How to make Ediff work the way YOU want. +* Credits:: Thanks to those who helped. +* Index:: + + +File: ediff.info, Node: Introduction, Next: Major Entry Points, Prev: Top, Up: Top + +1 Introduction +************** + +Ediff provides a convenient way for simultaneous browsing through the +differences between a pair (or a triple) of files or buffers (which are +called `variants' for our purposes). The files being compared, file-A, +file-B, and file-C (if applicable) are shown in separate windows (side +by side, one above the another, or in separate frames), and the +differences are highlighted as you step through them. You can also +copy difference regions from one buffer to another (and recover old +differences if you change your mind). + + Another powerful feature is the ability to merge a pair of files +into a third buffer. Merging with an ancestor file is also supported. +Furthermore, Ediff is equipped with directory-level capabilities that +allow the user to conveniently launch browsing or merging sessions on +groups of files in two (or three) different directories. + + In addition, Ediff can apply a patch to a file and then let you step +through both files, the patched and the original one, simultaneously, +difference-by-difference. You can even apply a patch right out of a +mail buffer, i.e., patches received by mail don't even have to be +saved. Since Ediff lets you copy differences between variants, you +can, in effect, apply patches selectively (i.e., you can copy a +difference region from `file.orig' to `file', thereby undoing any +particular patch that you don't like). + + Ediff even understands multi-file patches and can apply them +interactively! (Ediff can recognize multi-file patches only if they +are in the context format or GNU unified format. All other patches are +treated as 1-file patches. Ediff is [hopefully] using the same +algorithm as `patch' to determine which files need to be patched.) + + Ediff is aware of version control, which lets you compare files with +their older versions. Ediff also works with remote and compressed +files, automatically ftp'ing them over and uncompressing them. *Note +Remote and Compressed Files::, for details. + + This package builds upon ideas borrowed from Emerge, and several of +Ediff's functions are adaptations from Emerge. Although Ediff subsumes +and greatly extends Emerge, much of the functionality in Ediff is +influenced by Emerge. The architecture and the interface are, of +course, drastically different. + + +File: ediff.info, Node: Major Entry Points, Next: Session Commands, Prev: Introduction, Up: Top + +2 Major Entry Points +******************** + +When Ediff starts up, it displays a small control window, which accepts +the Ediff commands and two or three windows displaying the files to be +compared or merged. The control window can be in its own small frame or +it can be part of a bigger frame that displays other buffers. In any +case, it is important that the control window be active (i.e., be the +one receiving the keystrokes) when you use Ediff. You can switch to +other Emacs buffers at will and even edit the files currently being +compared with Ediff and then switch back to Ediff at any time by +activating the appropriate Emacs windows. + + Ediff can be invoked interactively using the following functions, +which can be run either from the minibuffer or from the menu bar. In +the menu bar, all Ediff's entry points belong to three submenus of the +Tools menu: Compare, Merge, and Apply Patch. + +`ediff-files' +`ediff' + Compare two files. + +`ediff-backup' + Compare a file with its backup. If there are several numerical + backups, use the latest. If the file is itself a backup, then + compare it with its original. + +`ediff-buffers' + Compare two buffers. + +`ediff-files3' +`ediff3' + Compare three files. + +`ediff-buffers3' + Compare three buffers. + +`edirs' +`ediff-directories' + Compare files common to two directories. + +`edirs3' +`ediff-directories3' + Compare files common to three directories. + +`edir-revisions' +`ediff-directory-revisions' + Compare versions of files in a given directory. Ediff selects + only the files that are under version control. + +`edir-merge-revisions' +`ediff-merge-directory-revisions' + Merge versions of files in a given directory. Ediff selects only + the files that are under version control. + +`edir-merge-revisions-with-ancestor' +`ediff-merge-directory-revisions-with-ancestor' + Merge versions of files in a given directory using other versions + as ancestors. Ediff selects only the files that are under version + control. + +`ediff-windows-wordwise' + Compare windows word-by-word. + +`ediff-windows-linewise' + Compare windows line-by-line. + +`ediff-regions-wordwise' + Compare regions word-by-word. The regions can come from the same + buffer and they can even overlap. You will be asked to specify + the buffers that contain the regions, which you want to compare. + For each buffer, you will also be asked to mark the regions to be + compared. Pay attention to the messages that appear in the + minibuffer. + +`ediff-regions-linewise' + Similar to `ediff-windows-linewise', but compares the regions + line-by-line. See `ediff-windows-linewise' for more details. + +`ediff-revision' + Compare versions of the current buffer, if the buffer is visiting + a file under version control. + +`ediff-patch-file' +`epatch' + Patch a file or multiple files, then compare. If the patch + applies to just one file, Ediff will invoke a regular comparison + session. If it is a multi-file patch, then a session group + interface will be used and the user will be able to patch the + files selectively. *Note Session Groups::, for more details. + + Since the patch might be in a buffer or a file, you will be asked + which is the case. To avoid this extra prompt, you can invoke this + command with a prefix argument. With an odd prefix argument, + Ediff assumes the patch is in a file; with an even argument, a + buffer is assumed. + + Note that `ediff-patch-file' will actually use the `patch' utility + to change the original files on disk. This is not that dangerous, + since you will always have the original contents of the file saved + in another file that has the extension `.orig'. Furthermore, if + the file is under version control, then you can always back out to + one of the previous versions (see the section on Version Control in + the Emacs manual). + + `ediff-patch-file' is careful about versions control: if the file + to be patched is checked in, then Ediff will offer to check it + out, because failing to do so may result in the loss of the + changes when the file is checked out the next time. + + If you don't intend to modify the file via the patch and just want + to see what the patch is all about (and decide later), then + `ediff-patch-buffer' might be a better choice. + +`ediff-patch-buffer' +`epatch-buffer' + Patch a buffer, then compare. The buffer being patched and the + file visited by that buffer (if any) is _not_ modified. The + result of the patch appears in some other buffer that has the name + ending with __patched_. + + This function would refuse to apply a multifile patch to a buffer. + Use `ediff-patch-file' for that (and when you want the original + file to be modified by the `patch' utility). + + Since the patch might be in a buffer or a file, you will be asked + which is the case. To avoid this extra prompt, you can invoke this + command with a prefix argument. With an odd prefix argument, + Ediff assumes the patch is in a file; with an even argument, a + buffer is assumed. + +`ediff-merge-files' +`ediff-merge' + Merge two files. + +`ediff-merge-files-with-ancestor' +`ediff-merge-with-ancestor' + Like `ediff-merge', but with a third ancestor file. + +`ediff-merge-buffers' + Merge two buffers. + +`ediff-merge-buffers-with-ancestor' + Same but with ancestor. + +`edirs-merge' +`ediff-merge-directories' + Merge files common to two directories. + +`edirs-merge-with-ancestor' +`ediff-merge-directories-with-ancestor' + Same but using files in a third directory as ancestors. If a + pair of files doesn't have an ancestor in the ancestor-directory, + you will still be able to merge them without the ancestor. + +`ediff-merge-revisions' + Merge two versions of the file visited by the current buffer. + +`ediff-merge-revisions-with-ancestor' + Same but with ancestor. + +`ediff-documentation' + Brings up this manual. + +`ediff-show-registry' +`eregistry' + Brings up Ediff session registry. This feature enables you to + quickly find and restart active Ediff sessions. + +If you want Ediff to be loaded from the very beginning of your Emacs +session, you should put this line in your `~/.emacs' file: + + (require 'ediff) + +Otherwise, Ediff will be loaded automatically when you use one of the +above functions, either directly or through the menus. + + When the above functions are invoked, the user is prompted for all +the necessary information--typically the files or buffers to compare, +merge, or patch. Ediff tries to be smart about these prompts. For +instance, in comparing/merging files, it will offer the visible buffers +as defaults. In prompting for files, if the user enters a directory, +the previously input file name will be appended to that directory. In +addition, if the variable `ediff-use-last-dir' is not `nil', Ediff will +offer previously entered directories as defaults (which will be +maintained separately for each type of file, A, B, or C). + + All the above functions use the POSIX `diff' or `diff3' programs to +find differences between two files. They process the `diff' output and +display it in a convenient form. At present, Ediff understands only +the plain output from diff. Options such as `-c' are not supported, +nor is the format produced by incompatible file comparison programs +such as the VMS version of `diff'. + + The functions `ediff-files', `ediff-buffers', `ediff-files3', +`ediff-buffers3' first display the coarse, line-based difference +regions, as reported by the `diff' program. The total number of +difference regions and the current difference number are always +displayed in the mode line of the control window. + + Since `diff' may report fairly large chunks of text as being +different, even though the difference may be localized to just a few +words or even to the white space or line breaks, Ediff further +_refines_ the regions to indicate which exact words differ. If the +only difference is in the white space and line breaks, Ediff says so. + + On a color display, fine differences are highlighted with color; on a +monochrome display, they are underlined. *Note Highlighting Difference +Regions::, for information on how to customize this. + + The commands `ediff-windows-wordwise', `ediff-windows-linewise', +`ediff-regions-wordwise' and `ediff-regions-linewise' do comparison on +parts of existing Emacs buffers. The commands `ediff-windows-wordwise' +and `ediff-regions-wordwise' are intended for relatively small segments +of buffers (e.g., up to 100 lines, depending on the speed of your +machine), as they perform comparison on the basis of words rather than +lines. (Word-wise comparison of large chunks of text can be slow.) + + To compare large regions, use `ediff-regions-linewise'. This +command displays differences much like `ediff-files' and +`ediff-buffers'. + + The functions `ediff-patch-file' and `ediff-patch-buffer' apply a +patch to a file or a buffer and then run Ediff on the appropriate +files/buffers, displaying the difference regions. + + The entry points `ediff-directories', `ediff-merge-directories', +etc., provide a convenient interface for comparing and merging files in +different directories. The user is presented with Dired-like interface +from which one can run a group of related Ediff sessions. + + For files under version control, `ediff-revision' lets you compare +the file visited by the current buffer to one of its checked-in +versions. You can also compare two checked-in versions of the visited +file. Moreover, the functions `ediff-directory-revisions', +`ediff-merge-directory-revisions', etc., let you run a group of related +Ediff sessions by taking a directory and comparing (or merging) +versions of files in that directory. + + +File: ediff.info, Node: Session Commands, Next: Registry of Ediff Sessions, Prev: Major Entry Points, Up: Top + +3 Session Commands +****************** + +All Ediff commands are displayed in a Quick Help window, unless you type +`?' to shrink the window to just one line. You can redisplay the help +window by typing `?' again. The Quick Help commands are detailed below. + + Many Ediff commands take numeric prefix arguments. For instance, if +you type a number, say 3, and then `j' (`ediff-jump-to-difference'), +Ediff moves to the third difference region. Typing 3 and then `a' +(`ediff-diff-to-diff') copies the 3d difference region from variant A +to variant B. Likewise, 4 followed by `ra' restores the 4th difference +region in buffer A (if it was previously written over via the command +`a'). + + Some commands take negative prefix arguments as well. For instance, +typing `-' and then `j' will make the last difference region current. +Typing `-2' then `j' makes the penultimate difference region current, +etc. + + Without the prefix argument, all commands operate on the currently +selected difference region. You can make any difference region current +using the various commands explained below. + + For some commands, the actual value of the prefix argument is +immaterial. However, if supplied, the prefix argument may modify the +command (see `ga', `gb', and `gc'). + +* Menu: + +* Quick Help Commands:: Frequently used commands. +* Other Session Commands:: Commands that are not bound to keys. + + +File: ediff.info, Node: Quick Help Commands, Next: Other Session Commands, Up: Session Commands + +3.1 Quick Help Commands +======================= + +`?' + Toggles the Ediff Quick Help window ON and OFF. + +`G' + Prepares a mail buffer for sending a praise or a curse to the + Ediff maintainer. + +`E' + Brings up the top node of this manual, where you can find further + information on the various Ediff functions and advanced issues, + such as customization, session groups, etc. + +`v' + Scrolls up buffers A and B (and buffer C where appropriate) in a + coordinated fashion. + +`V' + Scrolls the buffers down. + +`<' + Scrolls the buffers to the left simultaneously. + +`>' + Scrolls buffers to the right. + +`wd' + Saves the output from the diff utility, for further reference. + + With prefix argument, saves the plain output from `diff' (see + `ediff-diff-program' and `ediff-diff-options'). Without the + argument, it saves customized `diff' output (see + `ediff-custom-diff-program' and `ediff-custom-diff-options'), if + it is available. + +`wa' + Saves buffer A, if it was modified. + +`wb' + Saves buffer B, if it was modified. + +`wc' + Saves buffer C, if it was modified (if you are in a session that + compares three files simultaneously). + +`a' + _In comparison sessions:_ Copies the current difference region (or + the region specified as the prefix to this command) from buffer A + to buffer B. Ediff saves the old contents of buffer B's region; + it can be restored via the command `rb', which see. + + _In merge sessions:_ Copies the current difference region (or the + region specified as the prefix to this command) from buffer A to + the merge buffer. The old contents of this region in buffer C can + be restored via the command `r'. + +`b' + Works similarly, but copies the current difference region from + buffer B to buffer A (in _comparison sessions_) or the merge + buffer (in _merge sessions_). + + Ediff saves the old contents of the difference region copied over; + it can be reinstated via the command `ra' in comparison sessions + and `r' in merge sessions. + +`ab' + Copies the current difference region (or the region specified as + the prefix to this command) from buffer A to buffer B. This (and + the next five) command is enabled only in sessions that compare + three files simultaneously. The old region in buffer B is saved + and can be restored via the command `rb'. + +`ac' + Copies the difference region from buffer A to buffer C. The old + region in buffer C is saved and can be restored via the command + `rc'. + +`ba' + Copies the difference region from buffer B to buffer A. The old + region in buffer A is saved and can be restored via the command + `ra'. + +`bc' + Copies the difference region from buffer B to buffer C. The + command `rc' undoes this. + +`ca' + Copies the difference region from buffer C to buffer A. The + command `ra' undoes this. + +`cb' + Copies the difference region from buffer C to buffer B. The + command `rb' undoes this. + +`p' +`DEL' + Makes the previous difference region current. + +`n' +`SPC' + Makes the next difference region current. + +`j' +`-j' +`Nj' + Makes the very first difference region current. + + `-j' makes the last region current. Typing a number, N, and then + `j' makes the difference region N current. Typing -N (a negative + number) then `j' makes current the region Last - N. + +`ga' + Makes current the difference region closest to the position of the + point in buffer A. + + However, with a prefix argument, Ediff would position all variants + around the area indicated by the current point in buffer A: if the + point is inside a difference region, then the variants will be + positioned at this difference region. If the point is not in any + difference region, then it is in an area where all variants agree + with each other. In this case, the variants will be positioned so + that each would display this area (of agreement). + +`gb' + Makes current the difference region closest to the position of the + point in buffer B. + + With a prefix argument, behaves like `ga', but with respect to + buffer B. + +`gc' + _In merge sessions:_ makes current the difference region closest + to the point in the merge buffer. + + _In 3-file comparison sessions:_ makes current the region closest + to the point in buffer C. + + With a prefix argument, behaves like `ga', but with respect to + buffer C. + +`!' + Recomputes the difference regions, bringing them up to date. This + is often needed because it is common to do all sorts of editing + during Ediff sessions, so after a while, the highlighted + difference regions may no longer reflect the actual differences + among the buffers. + +`*' + Forces refinement of the current difference region, which + highlights the exact words of disagreement among the buffers. + With a negative prefix argument, unhighlights the current region. + + Forceful refinement may be needed if Ediff encounters a difference + region that is larger than `ediff-auto-refine-limit'. In this + situation, Ediff doesn't do automatic refinement in order to + improve response time. (Ediff doesn't auto-refine on dumb + terminals as well, but `*' still works there. However, the only + useful piece of information it can tell you is whether or not the + difference regions disagree only in the amount of white space.) + + This command is also useful when the highlighted fine differences + are no longer current, due to user editing. + +`m' + Displays the current Ediff session in a frame as wide as the + physical display. This is useful when comparing files + side-by-side. Typing `m' again restores the original size of the + frame. + +`|' + Toggles the horizontal/vertical split of the Ediff display. + Horizontal split is convenient when it is possible to compare files + side-by-side. If the frame in which files are displayed is too + narrow and lines are cut off, typing `m' may help some. + +`@' + Toggles auto-refinement of difference regions (i.e., automatic + highlighting of the exact words that differ among the variants). + Auto-refinement is turned off on devices where Emacs doesn't + support highlighting. + + On slow machines, it may be advantageous to turn auto-refinement + off. The user can always forcefully refine specific difference + regions by typing `*'. + +`h' + Cycles between full highlighting, the mode where fine differences + are not highlighted (but computed), and the mode where + highlighting is done with ASCII strings. The latter is not really + recommended, unless on a dumb TTY. + +`r' + Restores the old contents of the region in the merge buffer. (If + you copied a difference region from buffer A or B into the merge + buffer using the commands `a' or `b', Ediff saves the old contents + of the region in case you change your mind.) + + This command is enabled in merge sessions only. + +`ra' + Restores the old contents of the current difference region in + buffer A, which was previously saved when the user invoked one of + these commands: `b', `ba', `ca', which see. This command is + enabled in comparison sessions only. + +`rb' + Restores the old contents of the current difference region in + buffer B, which was previously saved when the user invoked one of + these commands: `a', `ab', `cb', which see. This command is + enabled in comparison sessions only. + +`rc' + Restores the old contents of the current difference region in + buffer C, which was previously saved when the user invoked one of + these commands: `ac', `bc', which see. This command is enabled in + 3-file comparison sessions only. + +`##' + Tell Ediff to skip over regions that disagree among themselves + only in the amount of white space and line breaks. + + Even though such regions will be skipped over, you can still jump + to any one of them by typing the region number and then `j'. + Typing `##' again puts Ediff back in the original state. + +`#c' + Toggle case sensitivity in the diff program. All diffs are + recomputed. Case sensitivity is controlled by the variables + `ediff-ignore-case-option', `ediff-ignore-case-option3', and + `ediff-ignore-case', which are explained elsewhere. + +`#h' +`#f' + Ediff works hard to ameliorate the effects of boredom in the + workplace... + + Quite often differences are due to identical replacements (e.g., + the word `foo' is replaced with the word `bar' everywhere). If + the number of regions with such boring differences exceeds your + tolerance threshold, you may be tempted to tell Ediff to skip + these regions altogether (you will still be able to jump to them + via the command `j'). The above commands, `#h' and `#f', may well + save your day! + + `#h' prompts you to specify regular expressions for each variant. + Difference regions where each variant's region matches the + corresponding regular expression will be skipped from then on. + (You can also tell Ediff to skip regions where at least one + variant matches its regular expression.) + + `#f' does dual job: it focuses on regions that match the + corresponding regular expressions. All other regions will be + skipped over. *Note Selective Browsing::, for more. + +`A' + Toggles the read-only property in buffer A. If file A is under + version control and is checked in, it is checked out (with your + permission). + +`B' + Toggles the read-only property in buffer B. If file B is under + version control and is checked in, it is checked out. + +`C' + Toggles the read-only property in buffer C (in 3-file comparison + sessions). If file C is under version control and is checked in, + it is checked out. + +`~' + Swaps the windows where buffers A and B are displayed. If you are + comparing three buffers at once, then this command would rotate + the windows among buffers A, B, and C. + +`i' + Displays all kinds of useful data about the current Ediff session. + +`D' + Runs `ediff-custom-diff-program' on the variants and displays the + buffer containing the output. This is useful when you must send + the output to your Mom. + + With a prefix argument, displays the plain `diff' output. *Note + Patch and Diff Programs::, for details. + +`R' + Displays a list of currently active Ediff sessions--the Ediff + Registry. You can then restart any of these sessions by either + clicking on a session record or by putting the cursor over it and + then typing the return key. + + (Some poor souls leave so many active Ediff sessions around that + they loose track of them completely... The `R' command is + designed to save these people from the recently discovered Ediff + Proficiency Syndrome.) + + Typing `R' brings up Ediff Registry only if it is typed into an + Ediff Control Panel. If you don't have a control panel handy, + type this in the minibuffer: `M-x eregistry'. *Note Registry of + Ediff Sessions::. + +`M' + Shows the session group buffer that invoked the current Ediff + session. *Note Session Groups::, for more information on session + groups. + +`z' + Suspends the current Ediff session. (If you develop a condition + known as Repetitive Ediff Injury--a serious but curable + illness--you must change your current activity. This command + tries hard to hide all Ediff-related buffers.) + + The easiest way to resume a suspended Ediff session is through the + registry of active sessions. *Note Registry of Ediff Sessions::, + for details. + +`q' + Terminates this Ediff session. With a prefix argument + (e.g.,`1q'), asks if you also want to delete the buffers of the + variants. Modified files and the results of merges are never + deleted. + +`%' + Toggles narrowing in Ediff buffers. Ediff buffers may be narrowed + if you are comparing only parts of these buffers via the commands + `ediff-windows-*' and `ediff-regions-*', which see. + +`C-l' + Restores the usual Ediff window setup. This is the quickest way + to resume an Ediff session, but it works only if the control panel + of that session is visible. + +`$$' + While merging with an ancestor file, Ediff is determined to reduce + user's wear and tear by saving him and her much of unproductive, + repetitive typing. If it notices that, say, file A's difference + region is identical to the same difference region in the ancestor + file, then the merge buffer will automatically get the difference + region taken from buffer B. The rationale is that this difference + region in buffer A is as old as that in the ancestor buffer, so + the contents of that region in buffer B represents real change. + + You may want to ignore such `obvious' merges and concentrate on + difference regions where both files `clash' with the ancestor, + since this means that two different people have been changing this + region independently and they had different ideas on how to do + this. + + The above command does this for you by skipping the regions where + only one of the variants clashes with the ancestor but the other + variant agrees with it. Typing `$$' again undoes this setting. + +`$*' + When merging files with large number of differences, it is + sometimes convenient to be able to skip the difference regions for + which you already decided which variant is most appropriate. + Typing `$*' will accomplish precisely this. + + To be more precise, this toggles the check for whether the current + merge is identical to its default setting, as originally decided + by Ediff. For instance, if Ediff is merging according to the + `combined' policy, then the merge region is skipped over if it is + different from the combination of the regions in buffers A and B. + (Warning: swapping buffers A and B will confuse things in this + respect). If the merge region is marked as `prefer-A' then this + region will be skipped if it differs from the current difference + region in buffer A, etc. + +`/' + Displays the ancestor file during merges. + +`&' + In some situations, such as when one of the files agrees with the + ancestor file on a difference region and the other doesn't, Ediff + knows what to do: it copies the current difference region from the + second buffer into the merge buffer. + + In other cases, the right course of action is not that clearcut, + and Ediff would use a default action. The above command changes + the default action. The default action can be `default-A' (choose + the region from buffer A), `default-B' (choose the region from + buffer B), or `combined' (combine the regions from the two + buffers). *Note Merging and diff3::, for further details. + + The command `&' also affects the regions in the merge buffers that + have `default-A', `default-B', or `combined' status, provided they + weren't changed with respect to the original. For instance, if + such a region has the status `default-A' then changing the default + action to `default-B' will also replace this merge-buffer's region + with the corresponding region from buffer B. + +`s' + Causes the merge window shrink to its minimum size, thereby + exposing as much of the variant buffers as possible. Typing `s' + again restores the original size of that window. + + With a positive prefix argument, this command enlarges the merge + window. E.g., `4s' increases the size of the window by about 4 + lines, if possible. With a negative numeric argument, the size of + the merge window shrinks by that many lines, if possible. Thus, + `-s' shrinks the window by about 1 line and `-3s' by about 3 lines. + + This command is intended only for temporary viewing; therefore, + Ediff restores window C to its original size whenever it makes any + other change in the window configuration. However, redisplaying + (`C-l') or jumping to another difference does not affect window + C's size. + + The split between the merge window and the variant windows is + controlled by the variable `ediff-merge-window-share', which see. + +`+' + Combines the difference regions from buffers A and B and copies the + result into the merge buffer. *Note Merging and diff3::, and the + variables `ediff-combine-diffs' and `ediff-combination-pattern'. + +`=' + You may run into situations when a large chunk of text in one file + has been edited and then moved to a different place in another + file. In such a case, these two chunks of text are unlikely to + belong to the same difference region, so the refinement feature of + Ediff will not be able to tell you what exactly differs inside + these chunks. Since eyeballing large pieces of text is contrary + to human nature, Ediff has a special command to help reduce the + risk of developing a cataract. + + In other situations, the currently highlighted region might be big + and you might want to reconcile of them interactively. + + All of this can be done with the above command, `=', which + compares regions within Ediff buffers. Typing `=' creates a child + Ediff session for comparing regions in buffers A, B, or C as + follows. + + First, you will be asked whether you want to compare the fine + differences between the currently highlighted buffers on a + word-by-word basis. If you accept, a child Ediff session will + start using the currently highlighted regions. Ediff will let you + step over the differences word-wise. + + If you reject the offer, you will be asked to select regions of + your choice. + + _If you are comparing 2 files or buffers:_ Ediff will ask you to + select regions in buffers A and B. + + _If you are comparing 3 files or buffers simultaneously:_ Ediff + will ask you to choose buffers and then select regions inside + those buffers. + + _If you are merging files or buffers (with or without ancestor):_ + Ediff will ask you to choose which buffer (A or B) to compare with + the merge buffer and then select regions in those buffers. + + + +File: ediff.info, Node: Other Session Commands, Prev: Quick Help Commands, Up: Session Commands + +3.2 Other Session Commands +========================== + +The following commands can be invoked from within any Ediff session, +although some of them are not bound to a key. + +`eregistry' +`ediff-show-registry' + This command brings up the registry of active Ediff sessions. + Ediff registry is a device that can be used to resume any active + Ediff session (which may have been postponed because the user + switched to some other activity). This command is also useful for + switching between multiple active Ediff sessions that are run at + the same time. The function `eregistry' is an alias for + `ediff-show-registry'. *Note Registry of Ediff Sessions::, for + more information on this registry. + +`ediff-toggle-multiframe' + Changes the display from the multi-frame mode (where the quick + help window is in a separate frame) to the single-frame mode + (where all Ediff buffers share the same frame), and vice versa. + See `ediff-window-setup-function' for details on how to make + either of these modes the default one. + + This function can also be invoked from the Menubar. However, in + some cases, the change will take place only after you execute one + of the Ediff commands, such as going to the next difference or + redisplaying. + +`ediff-toggle-use-toolbar' + Available in XEmacs only. The Ediff toolbar provides quick access + to some of the common Ediff functions. This function toggles the + display of the toolbar. If invoked from the menubar, the function + may take sometimes effect only after you execute an Ediff command, + such as going to the next difference. + +`ediff-use-toolbar-p' + The use of the toolbar can also be specified via the variable + `ediff-use-toolbar-p' (default is `t'). This variable can be set + only in `.emacs' -- do *not* change it interactively. Use the + function `ediff-toggle-use-toolbar' instead. + +`ediff-revert-buffers-then-recompute-diffs' + This command reverts the buffers you are comparing and recomputes + their differences. It is useful when, after making changes, you + decided to make a fresh start, or if at some point you changed the + files being compared but want to discard any changes to comparison + buffers that were done since then. + + This command normally asks for confirmation before reverting files. + With a prefix argument, it reverts files without asking. + +`ediff-profile' + Ediff has an admittedly primitive (but useful) facility for + profiling Ediff's commands. It is meant for Ediff + maintenance--specifically, for making it run faster. The function + `ediff-profile' toggles profiling of ediff commands. + + +File: ediff.info, Node: Registry of Ediff Sessions, Next: Session Groups, Prev: Session Commands, Up: Top + +4 Registry of Ediff Sessions +**************************** + +Ediff maintains a registry of all its invocations that are still +_active_. This feature is very convenient for switching among active +Ediff sessions or for quickly restarting a suspended Ediff session. + + The focal point of this activity is a buffer called _*Ediff +Registry*_. You can display this buffer by typing `R' in any Ediff +Control Buffer or Session Group Buffer (*note Session Groups::), or by +typing `M-x eregistry' into the Minibuffer. The latter would be the +fastest way to bring up the registry buffer if no control or group +buffer is displayed in any of the visible Emacs windows. If you are in +a habit of running multiple long Ediff sessions and often need to +suspend, resume, or switch between them, it may be a good idea to have +the registry buffer permanently displayed in a separate, dedicated +window. + + The registry buffer has several convenient key bindings. For +instance, clicking mouse button 2 or typing `RET' or `v' over any +session record resumes that session. Session records in the registry +buffer provide a fairly complete description of each session, so it is +usually easy to identify the right session to resume. + + Other useful commands are bound to `SPC' (next registry record) and +`DEL' (previous registry record). There are other commands as well, +but you don't need to memorize them, since they are listed at the top of +the registry buffer. + + +File: ediff.info, Node: Session Groups, Next: Remote and Compressed Files, Prev: Registry of Ediff Sessions, Up: Top + +5 Session Groups +**************** + +Several major entries of Ediff perform comparison and merging on +directories. On entering `ediff-directories', `ediff-directories3', +`ediff-merge-directories', `ediff-merge-directories-with-ancestor', +`ediff-directory-revisions', `ediff-merge-directory-revisions', or +`ediff-merge-directory-revisions-with-ancestor', the user is presented +with a Dired-like buffer that lists files common to the directories +involved along with their sizes. (The list of common files can be +further filtered through a regular expression, which the user is +prompted for.) We call this buffer _Session Group Panel_ because all +Ediff sessions associated with the listed files will have this buffer +as a common focal point. + + Clicking button 2 or typing `RET' or `v' over a record describing +files invokes Ediff in the appropriate mode on these files. You can +come back to the session group buffer associated with a particular +invocation of Ediff by typing `M' in Ediff control buffer of that +invocation. + + Many commands are available in the session group buffer; some are +applicable only to certain types of work. The relevant commands are +always listed at the top of each session group buffer, so there is no +need to memorize them. + + In directory comparison or merging, a session group panel displays +only the files common to all directories involved. The differences are +kept in a separate _directory difference buffer_ and are conveniently +displayed by typing `D' to the corresponding session group panel. +Thus, as an added benefit, Ediff can be used to compare the contents of +up to three directories. + + Sometimes it is desirable to copy some files from one directory to +another without exiting Ediff. The _directory difference buffer_, which +is displayed by typing `D' as discussed above, can be used for this +purpose. If a file is, say, in Ediff's Directory A, but is missing in +Ediff's Directory B (Ediff will refuse to override existing files), then +typing `C' or clicking mouse button 2 over that file (which must be +displayed in directory difference buffer) will copy that file from +Directory A to Directory B. + + Session records in session group panels are also marked with `+', for +active sessions, and with `-', for finished sessions. + + Sometimes, it is convenient to exclude certain sessions from a group. +Usually this happens when the user doesn't intend to run Ediff of +certain files in the group, and the corresponding session records just +add clutter to the session group buffer. To help alleviate this +problem, the user can type `h' to mark a session as a candidate for +exclusion and `x' to actually hide the marked sessions. There actions +are reversible: with a prefix argument, `h' unmarks the session under +the cursor, and `x' brings the hidden sessions into the view (`x' +doesn't unmark them, though, so the user has to explicitly unmark the +sessions of interest). + + Group sessions also understand the command `m', which marks sessions +for future operations (other than hiding) on a group of sessions. At +present, the only such group-level operation is the creation of a +multi-file patch. + + For group sessions created to merge files, Ediff can store all merges +automatically in a directory. The user is asked to specify such +directory if the value of `ediff-autostore-merges' is non-`nil'. If +the value is `nil', nothing is done to the merge buffers--it will be +the user's responsibility to save them. If the value is `t', the user +will be asked where to save the merge buffers in all merge jobs, even +those that do not originate from a session group. It the value is +neither `nil' nor `t', the merge buffer is saved _only_ if this merge +session was invoked from a session group. This behavior is implemented +in the function `ediff-maybe-save-and-delete-merge', which is a hook in +`ediff-quit-merge-hook'. The user can supply a different hook, if +necessary. + + The variable `ediff-autostore-merges' is buffer-local, so it can be +set on a per-buffer basis. Therefore, use `setq-default' to change +this variable globally. + + A multi-file patch is a concatenated output of several runs of the +Unix `diff' command (some versions of `diff' let you create a +multi-file patch in just one run). Ediff facilitates creation of +multi-file patches as follows. If you are in a session group buffer +created in response to `ediff-directories' or +`ediff-directory-revisions', you can mark (by typing `m') the desired +Ediff sessions and then type `P' to create a multi-file patch of those +marked sessions. Ediff will then display a buffer containing the patch. +The patch is generated by invoking `diff' on all marked individual +sessions (represented by files) and session groups (represented by +directories). Ediff will also recursively descend into any _unmarked_ +session group and will search for marked sessions there. In this way, +you can create multi-file patches that span file subtrees that grow out +of any given directory. + + In an `ediff-directories' session, it is enough to just mark the +requisite sessions. In `ediff-directory-revisions' revisions, the +marked sessions must also be active, or else Ediff will refuse to +produce a multi-file patch. This is because, in the latter-style +sessions, there are many ways to create diff output, and it is easier +to handle by running Ediff on the inactive sessions. + + Last, but not least, by typing `==', you can quickly find out which +sessions have identical entries, so you won't have to run Ediff on those +sessions. This, however, works only on local, uncompressed files. For +compressed or remote files, this command won't report anything. +Likewise, you can use `=h' to mark sessions with identical entries for +hiding or, with `=m', for further operations. + + The comparison operations `==', `=h', and `=m' can recurse into +subdirectories to see if they have identical contents (so the user will +not need to descend into those subdirectories manually). These commands +ask the user whether or not to do a recursive descent. + + +File: ediff.info, Node: Remote and Compressed Files, Next: Customization, Prev: Session Groups, Up: Top + +6 Remote and Compressed Files +***************************** + +Ediff works with remote, compressed, and encrypted files. Ediff +supports `ange-ftp.el', `jka-compr.el', `uncompress.el' and +`crypt++.el', but it may work with other similar packages as well. +This means that you can compare files residing on another machine, or +you can apply a patch to a file on another machine. Even the patch +itself can be a remote file! + + When patching compressed or remote files, Ediff does not rename the +source file (unlike what the `patch' utility would usually do). +Instead, the source file retains its name and the result of applying +the patch is placed in a temporary file that has the suffix `_patched' +attached. Generally, this applies to files that are handled using +black magic, such as special file handlers (ange-ftp and some +compression and encryption packages also use this method). + + Regular files are treated by the `patch' utility in the usual manner, +i.e., the original is renamed into `source-name.orig' and the result of +the patch is placed into the file source-name (`_orig' is used on +systems like VMS, DOS, etc.) + + +File: ediff.info, Node: Customization, Next: Credits, Prev: Remote and Compressed Files, Up: Top + +7 Customization +*************** + +Ediff has a rather self-explanatory interface, and in most cases you +won't need to change anything. However, should the need arise, there +are extensive facilities for changing the default behavior. + + Most of the customization can be done by setting various variables +in the `.emacs' file. Some customization (mostly window-related +customization and faces) can be done by putting appropriate lines in +`.Xdefaults', `.xrdb', or whatever X resource file is in use. + + With respect to the latter, please note that the X resource for +Ediff customization is `Ediff', _not_ `emacs'. *Note Window and Frame +Configuration::, *Note Highlighting Difference Regions::, for further +details. Please also refer to Emacs manual for the information on how +to set Emacs X resources. + +* Menu: + +* Hooks:: Customization via the hooks. +* Quick Help Customization:: How to customize Ediff's quick help feature. +* Window and Frame Configuration:: Controlling the way Ediff displays things. +* Selective Browsing:: Advanced browsing through difference regions. +* Highlighting Difference Regions:: Controlling highlighting. +* Narrowing:: Comparing regions, windows, etc. +* Refinement of Difference Regions:: How to control the refinement process. +* Patch and Diff Programs:: Changing the utilities that compute differences + and apply patches. +* Merging and diff3:: How to customize Ediff in its Merge Mode. +* Support for Version Control:: Changing the version control package. + You are not likely to do that. +* Customizing the Mode Line:: Changing the look of the mode line in Ediff. +* Miscellaneous:: Other customization. +* Notes on Heavy-duty Customization:: Customization for the gurus. + + +File: ediff.info, Node: Hooks, Next: Quick Help Customization, Prev: Customization, Up: Customization + +7.1 Hooks +========= + +The bulk of customization can be done via the following hooks: + +`ediff-load-hook' + This hook can be used to change defaults after Ediff is loaded. + +`ediff-before-setup-hook' + Hook that is run just before Ediff rearranges windows to its + liking. Can be used to save windows configuration. + +`ediff-keymap-setup-hook' + This hook can be used to alter bindings in Ediff's keymap, + `ediff-mode-map'. These hooks are run right after the default + bindings are set but before `ediff-load-hook'. The regular user + needs not be concerned with this hook--it is provided for + implementors of other Emacs packages built on top of Ediff. + +`ediff-before-setup-windows-hook' +`ediff-after-setup-windows-hook' + These two hooks are called before and after Ediff sets up its + window configuration. These hooks are run each time Ediff + rearranges windows to its liking. This happens whenever it detects + that the user changed the windows setup. + +`ediff-suspend-hook' +`ediff-quit-hook' + These two hooks are run when you suspend or quit Ediff. They can + be used to set desired window configurations, delete files Ediff + didn't want to clean up after exiting, etc. + + By default, `ediff-quit-hook' holds one hook function, + `ediff-cleanup-mess', which cleans after Ediff, as appropriate in + most cases. You probably won't want to change it, but you might + want to add other hook functions. + + Keep in mind that hooks executing before `ediff-cleanup-mess' start + in `ediff-control-buffer;' they should also leave + `ediff-control-buffer' as the current buffer when they finish. + Hooks that are executed after `ediff-cleanup-mess' should expect + the current buffer be either buffer A or buffer B. + `ediff-cleanup-mess' doesn't kill the buffers being compared or + merged (see `ediff-cleanup-hook', below). + +`ediff-cleanup-hook' + This hook is run just before `ediff-quit-hook'. This is a good + place to do various cleanups, such as deleting the variant buffers. + Ediff provides a function, `ediff-janitor', as one such possible + hook, which you can add to `ediff-cleanup-hook' with `add-hooks'. + + This function kills buffers A, B, and, possibly, C, if these + buffers aren't modified. In merge jobs, buffer C is never + deleted. However, the side effect of using this function is that + you may not be able to compare the same buffer in two separate + Ediff sessions: quitting one of them will delete this buffer in + another session as well. + +`ediff-quit-merge-hook' + This hook is called when Ediff quits a merge job. By default, the + value is `ediff-maybe-save-and-delete-merge', which is a function + that attempts to save the merge buffer according to the value of + `ediff-autostore-merges', as described later. + +`ediff-before-setup-control-frame-hook' +`ediff-after-setup-control-frame-hook' + These two hooks run before and after Ediff sets up the control + frame. They can be used to relocate Ediff control frame when + Ediff runs in a multiframe mode (i.e., when the control buffer is + in its own dedicated frame). Be aware that many variables that + drive Ediff are local to Ediff Control Panel + (`ediff-control-buffer'), which requires special care in writing + these hooks. Take a look at `ediff-default-suspend-hook' and + `ediff-default-quit-hook' to see what's involved. + +`ediff-startup-hook' + This hook is run at the end of Ediff startup. + +`ediff-select-hook' + This hook is run after Ediff selects the next difference region. + +`ediff-unselect-hook' + This hook is run after Ediff unselects the current difference + region. + +`ediff-prepare-buffer-hook' + This hook is run for each Ediff buffer (A, B, C) right after the + buffer is arranged. + +`ediff-display-help-hook' + Ediff runs this hook each time after setting up the help message. + It can be used to alter the help message for custom packages that + run on top of Ediff. + +`ediff-mode-hook' + This hook is run just after Ediff mode is set up in the control + buffer. This is done before any Ediff window is created. You can + use it to set local variables that alter the look of the display. + +`ediff-registry-setup-hook' + Hooks run after setting up the registry for all active Ediff + session. *Note Session Groups::, for details. + +`ediff-before-session-group-setup-hook' + Hooks run before setting up a control panel for a group of related + Ediff sessions. Can be used, for example, to save window + configuration to restore later. + +`ediff-after-session-group-setup-hook' + Hooks run after setting up a control panel for a group of related + Ediff sessions. *Note Session Groups::, for details. + +`ediff-quit-session-group-hook' + Hooks run just before exiting a session group. + +`ediff-meta-buffer-keymap-setup-hook' + Hooks run just after setting up the `ediff-meta-buffer-map' -- the + map that controls key bindings in the meta buffer. Since + `ediff-meta-buffer-map' is a local variable, you can set different + bindings for different kinds of meta buffers. + + +File: ediff.info, Node: Quick Help Customization, Next: Window and Frame Configuration, Prev: Hooks, Up: Customization + +7.2 Quick Help Customization +============================ + +Ediff provides quick help using its control panel window. Since this +window takes a fair share of the screen real estate, you can toggle it +off by typing `?'. The control window will then shrink to just one +line and a mode line, displaying a short help message. + + The variable `ediff-use-long-help-message' tells Ediff whether you +use the short message or the long one. By default, it is set to `nil', +meaning that the short message is used. Set this to `t', if you want +Ediff to use the long message by default. This property can always be +changed interactively, by typing `?' into Ediff Control Buffer. + + If you want to change the appearance of the help message on a +per-buffer basis, you must use `ediff-startup-hook' to change the value +of the variable `ediff-help-message', which is local to +`ediff-control-buffer'. + + +File: ediff.info, Node: Window and Frame Configuration, Next: Selective Browsing, Prev: Quick Help Customization, Up: Customization + +7.3 Window and Frame Configuration +================================== + +On a non-windowing display, Ediff sets things up in one frame, splitting +it between a small control window and the windows for buffers A, B, and +C. The split between these windows can be horizontal or vertical, +which can be changed interactively by typing `|' while the cursor is in +the control window. + + On a window display, Ediff sets up a dedicated frame for Ediff +Control Panel and then it chooses windows as follows: If one of the +buffers is invisible, it is displayed in the currently selected frame. +If a buffer is visible, it is displayed in the frame where it is +visible. If, according to the above criteria, the two buffers fall +into the same frame, then so be it--the frame will be shared by the +two. The same algorithm works when you type `C-l' (`ediff-recenter'), +`p' (`ediff-previous-difference'), `n' (`ediff-next-difference'), etc. + + The above behavior also depends on whether the current frame is +splittable, dedicated, etc. Unfortunately, the margin of this book is +too narrow to present the details of this remarkable algorithm. + + The upshot of all this is that you can compare buffers in one frame +or in different frames. The former is done by default, while the +latter can be achieved by arranging buffers A, B (and C, if applicable) +to be seen in different frames. Ediff respects these arrangements, +automatically adapting itself to the multi-frame mode. + + Ediff uses the following variables to set up its control panel +(a.k.a. control buffer, a.k.a. quick help window): + +`ediff-control-frame-parameters' + You can change or augment this variable including the font, color, + etc. The X resource name of Ediff Control Panel frames is + `Ediff'. Under X-windows, you can use this name to set up + preferences in your `~/.Xdefaults', `~/.xrdb', or whatever X + resource file is in use. Usually this is preferable to changing + `ediff-control-frame-parameters' directly. For instance, you can + specify in `~/.Xdefaults' the color of the control frame using the + resource `Ediff*background'. + + In general, any X resource pertaining the control frame can be + reached via the prefix `Ediff*'. + +`ediff-control-frame-position-function' + The preferred way of specifying the position of the control frame + is by setting the variable `ediff-control-frame-position-function' + to an appropriate function. The default value of this variable is + `ediff-make-frame-position'. This function places the control + frame in the vicinity of the North-East corner of the frame + displaying buffer A. + + + The following variables can be used to adjust the location produced +by `ediff-make-frame-position' and for related customization. + +`ediff-narrow-control-frame-leftward-shift' + Specifies the number of characters for shifting the control frame + from the rightmost edge of frame A when the control frame is + displayed as a small window. + +`ediff-wide-control-frame-rightward-shift' + Specifies the rightward shift of the control frame from the left + edge of frame A when the control frame shows the full menu of + options. + +`ediff-control-frame-upward-shift' + Specifies the number of pixels for the upward shift of the control + frame. + +`ediff-prefer-iconified-control-frame' + If this variable is `t', the control frame becomes iconified + automatically when you toggle the quick help message off. This + saves valuable real estate on the screen. Toggling help back will + deiconify the control frame. + + To start Ediff with an iconified Control Panel, you should set this + variable to `t' and `ediff-prefer-long-help-message' to `nil' + (*note Quick Help Customization::). This behavior is useful only + if icons are allowed to accept keybord input (which depend on the + window manager and other factors). + + To make more creative changes in the way Ediff sets up windows, you +can rewrite the function `ediff-setup-windows'. However, we believe +that detaching Ediff Control Panel from the rest and making it into a +separate frame offers an important opportunity by allowing you to +iconify that frame. The icon will usually accept all of the Ediff +commands, but will free up valuable real estate on your screen (this may +depend on your window manager, though). + + The following variable controls how windows are set up: + +`ediff-window-setup-function' + The multiframe setup is done by the + `ediff-setup-windows-multiframe' function, which is the default on + windowing displays. The plain setup, one where all windows are + always in one frame, is done by `ediff-setup-windows-plain', which + is the default on a non-windowing display (or in an xterm window). + In fact, under Emacs, you can switch freely between these two + setups by executing the command `ediff-toggle-multiframe' using + the Minibuffer of the Menubar. + + If you don't like any of these setups, write your own function. + See the documentation for `ediff-window-setup-function' for the + basic guidelines. However, writing window setups is not easy, so + you should first take a close look at `ediff-setup-windows-plain' + and `ediff-setup-windows-multiframe'. + + You can run multiple Ediff sessions at once, by invoking Ediff +several times without exiting previous Ediff sessions. Different +sessions may even operate on the same pair of files. + + Each session has its own Ediff Control Panel and all the regarding a +particular session is local to the associated control panel buffer. You +can switch between sessions by suspending one session and then switching +to another control panel. (Different control panel buffers are +distinguished by a numerical suffix, e.g., `Ediff Control Panel<3>'.) + + +File: ediff.info, Node: Selective Browsing, Next: Highlighting Difference Regions, Prev: Window and Frame Configuration, Up: Customization + +7.4 Selective Browsing +====================== + +Sometimes it is convenient to be able to step through only some +difference regions, those that match certain regular expressions, and +to ignore all others. On other occasions, you may want to ignore +difference regions that match some regular expressions, and to look +only at the rest. + + The commands `#f' and `#h' let you do precisely this. + + Typing `#f' lets you specify regular expressions that match +difference regions you want to focus on. We shall call these regular +expressions REGEXP-A, REGEXP-B and REGEXP-C. Ediff will then start +stepping through only those difference regions where the region in +buffer A matches REGEXP-A and/or the region in buffer B matches +REGEXP-B, etc. Whether `and' or `or' will be used depends on how you +respond to a question. + + When scanning difference regions for the aforesaid regular +expressions, Ediff narrows the buffers to those regions. This means +that you can use the expressions `\`' and `\'' to tie search to the +beginning or end of the difference regions. + + On the other hand, typing `#h' lets you specify (hide) uninteresting +regions. That is, if a difference region in buffer A matches REGEXP-A, +the corresponding region in buffer B matches REGEXP-B and (if +applicable) buffer C's region matches REGEXP-C, then the region will be +ignored by the commands `n'/ (`ediff-next-difference') and +`p'/ (`ediff-previous-difference') commands. + + Typing `#f' and `#h' toggles selective browsing on and off. + + Note that selective browsing affects only `ediff-next-difference' +and `ediff-previous-difference', i.e., the commands `n'/ and +`p'/. `#f' and `#h' do not change the position of the point in +the buffers. And you can still jump directly (using `j') to any +numbered difference. + + Users can supply their own functions to specify how Ediff should do +selective browsing. To change the default Ediff function, add a +function to `ediff-load-hook' which will do the following assignments: + + (setq ediff-hide-regexp-matches-function 'your-hide-function) + (setq ediff-focus-on-regexp-matches-function 'your-focus-function) + + *Useful hint*: To specify a regexp that matches everything, don't +simply type in response to a prompt. Typing tells Ediff to +accept the default value, which may not be what you want. Instead, you +should enter something like <^> or <$>. These match every line. + + You can use the status command, `i', to find out whether selective +browsing is currently in effect. + + The regular expressions you specified are kept in the local variables +`ediff-regexp-focus-A', `ediff-regexp-focus-B', `ediff-regexp-focus-C', +`ediff-regexp-hide-A', `ediff-regexp-hide-B', `ediff-regexp-hide-C'. +Their default value is the empty string (i.e., nothing is hidden or +focused on). To change the default, set these variables in `.emacs' +using `setq-default'. + + In addition to the ability to ignore regions that match regular +expressions, Ediff can be ordered to start skipping over certain +"uninteresting" difference regions. This is controlled by the following +variable: + +`ediff-ignore-similar-regions' + If `t', causes Ediff to skip over "uninteresting" difference + regions, which are the regions where the variants differ only in + the amount of the white space and newlines. This feature can be + toggled on/off interactively, via the command `##'. + + *Please note:* in order for this feature to work, auto-refining of +difference regions must be on, since otherwise Ediff won't know if there +are fine differences between regions. On devices where Emacs can +display faces, auto-refining is a default, but it is not turned on by +default on text-only terminals. In that case, you must explicitly turn +auto-refining on (such as, by typing `@'). + + *Reassurance:* If many such uninteresting regions appear in a row, +Ediff may take a long time to skip over them because it has to compute +fine differences of all intermediate regions. This delay does not +indicate any problem. + + Finally, Ediff can be told to ignore the case of the letters. This +behavior can be toggled with `#c' and it is controlled with three +variables: Toggle case sensitivity in the diff program. All diffs are +recomputed. Case sensitivity is controlled by the variables +`ediff-ignore-case-option', `ediff-ignore-case-option3', and +`ediff-ignore-case'. + + The variable `ediff-ignore-case-option' specifies the option to pass +to the diff program for comparing two files or buffers. For GNU `diff', +this option is `"-i"'. The variable `ediff-ignore-case-option3' +specifies the option to pass to the `diff3' program in order to make it +case-insensitive. GNU `diff3' does not have such an option, so when +merging or comparing three files with this program, ignoring the letter +case is not supported. + + The variable `ediff-ignore-case' controls whether Ediff starts out by +ignoring letter case or not. It can be set in `.emacs' using +`setq-default'. + + +File: ediff.info, Node: Highlighting Difference Regions, Next: Narrowing, Prev: Selective Browsing, Up: Customization + +7.5 Highlighting Difference Regions +=================================== + +The following variables control the way Ediff highlights difference +regions: + +`ediff-before-flag-bol' +`ediff-after-flag-eol' +`ediff-before-flag-mol' +`ediff-after-flag-mol' + These variables hold strings that Ediff uses to mark the beginning + and the end of the differences found in files A, B, and C on + devices where Emacs cannot display faces. Ediff uses different + flags to highlight regions that begin/end at the beginning/end of + a line or in a middle of a line. + +`ediff-current-diff-face-A' +`ediff-current-diff-face-B' +`ediff-current-diff-face-C' + Ediff uses these faces to highlight current differences on devices + where Emacs can display faces. These and subsequently described + faces can be set either in `.emacs' or in `.Xdefaults'. The X + resource for Ediff is `Ediff', _not_ `emacs'. Please refer to + Emacs manual for the information on how to set X resources. + +`ediff-fine-diff-face-A' +`ediff-fine-diff-face-B' +`ediff-fine-diff-face-C' + Ediff uses these faces to show the fine differences between the + current differences regions in buffers A, B, and C, respectively. + +`ediff-even-diff-face-A' +`ediff-even-diff-face-B' +`ediff-even-diff-face-C' +`ediff-odd-diff-face-A' +`ediff-odd-diff-face-B' +`ediff-odd-diff-face-C' + Non-current difference regions are displayed using these + alternating faces. The odd and the even faces are actually + identical on monochrome displays, because without colors options + are limited. So, Ediff uses italics to highlight non-current + differences. + +`ediff-force-faces' + Ediff generally can detect when Emacs is running on a device where + it can use highlighting with faces. However, if it fails to + determine that faces can be used, the user can set this variable + to `t' to make sure that Ediff uses faces to highlight differences. + +`ediff-highlight-all-diffs' + Indicates whether--on a windowind display--Ediff should highlight + differences using inserted strings (as on text-only terminals) or + using colors and highlighting. Normally, Ediff highlights all + differences, but the selected difference is highlighted more + visibly. One can cycle through various modes of highlighting by + typing `h'. By default, Ediff starts in the mode where all + difference regions are highlighted. If you prefer to start in the + mode where unselected differences are not highlighted, you should + set `ediff-highlight-all-diffs' to `nil'. Type `h' to restore + highlighting for all differences. + + Ediff lets you switch between the two modes of highlighting. That + is, you can switch interactively from highlighting using faces to + highlighting using string flags, and back. Of course, switching + has effect only under a windowing system. On a text-only terminal + or in an xterm window, the only available option is highlighting + with strings. + +If you want to change the default settings for `ediff-force-faces' and +`ediff-highlight-all-diffs', you must do it *before* Ediff is loaded. + + You can also change the defaults for the faces used to highlight the +difference regions. There are two ways to do this. The simplest and +the preferred way is to use the customization widget accessible from the +menubar. Ediff's customization group is located under "Tools", which in +turn is under "Programming". The faces that are used to highlight +difference regions are located in the "Highlighting" subgroup of the +Ediff customization group. + + The second, much more arcane, method to change default faces is to +include some Lisp code in `~/.emacs'. For instance, + + (setq ediff-current-diff-face-A + (copy-face 'bold-italic 'ediff-current-diff-face-A)) + +would use the pre-defined fase `bold-italic' to highlight the current +difference region in buffer A (this face is not a good choice, by the +way). + + If you are unhappy with just _some_ of the aspects of the default +faces, you can modify them when Ediff is being loaded using +`ediff-load-hook'. For instance: + + (add-hook 'ediff-load-hook + (lambda () + (set-face-foreground + ediff-current-diff-face-B "blue") + (set-face-background + ediff-current-diff-face-B "red") + (make-face-italic + ediff-current-diff-face-B))) + + *Please note:* to set Ediff's faces, use only `copy-face' or +`set/make-face-...' as shown above. Emacs' low-level face-manipulation +functions should be avoided. + + +File: ediff.info, Node: Narrowing, Next: Refinement of Difference Regions, Prev: Highlighting Difference Regions, Up: Customization + +7.6 Narrowing +============= + +If buffers being compared are narrowed at the time of invocation of +Ediff, `ediff-buffers' will preserve the narrowing range. However, if +`ediff-files' is invoked on the files visited by these buffers, that +would widen the buffers, since this command is defined to compare the +entire files. + + Calling `ediff-regions-linewise' or `ediff-windows-linewise', or the +corresponding `-wordwise' commands, narrows the variants to the +particular regions being compared. The original accessible ranges are +restored when you quit Ediff. During the command, you can toggle this +narrowing on and off with the `%' command. + + These two variables control this narrowing behavior: + +`ediff-start-narrowed' + If `t', Ediff narrows the display to the appropriate range when it + is invoked with an `ediff-regions...' or `ediff-windows...' + command. If `nil', these commands do not automatically narrow, + but you can still toggle narrowing on and off by typing `%'. + +`ediff-quit-widened' + Controls whether on quitting Ediff should restore the accessible + range that existed before the current invocation. + + +File: ediff.info, Node: Refinement of Difference Regions, Next: Patch and Diff Programs, Prev: Narrowing, Up: Customization + +7.7 Refinement of Difference Regions +==================================== + +Ediff has variables to control the way fine differences are +highlighted. This feature gives you control over the process of +refinement. Note that refinement ignores spaces, tabs, and newlines. + +`ediff-auto-refine' + This variable controls whether fine differences within regions are + highlighted automatically ("auto-refining"). The default is yes + (`on'). + + On a slow machine, automatic refinement may be painful. In that + case, you can turn auto-refining on or off interactively by typing + `@'. You can also turn off display of refining that has already + been done. + + When auto-refining is off, fine differences are shown only for + regions for which these differences have been computed and saved + before. If auto-refining and display of refining are both turned + off, fine differences are not shown at all. + + Typing `*' computes and displays fine differences for the current + difference region, regardless of whether auto-refining is turned + on. + +`ediff-auto-refine-limit' + If auto-refining is on, this variable limits the size of the + regions to be auto-refined. This guards against the possible + slowdown that may be caused by extraordinary large difference + regions. + + You can always refine the current region by typing `*'. + +`ediff-forward-word-function' + This variable controls how fine differences are computed. The + value must be a Lisp function that determines how the current + difference region should be split into words. + + Fine differences are computed by first splitting the current + difference region into words and then passing the result to + `ediff-diff-program'. For the default forward word function + (which is `ediff-forward-word'), a word is a string consisting of + letters, `-', or `_'; a string of punctuation symbols; a string of + digits, or a string consisting of symbols that are neither space, + nor a letter. + + This default behavior is controlled by four variables: + `ediff-word-1', ..., `ediff-word-4'. See the on-line + documentation for these variables and for the function + `ediff-forward-word' for an explanation of how to modify these + variables. + + Sometimes, when a region has too many differences between the +variants, highlighting of fine differences is inconvenient, especially +on color displays. If that is the case, type `*' with a negative +prefix argument. This unhighlights fine differences for the current +region. + + To unhighlight fine differences in all difference regions, use the +command `@'. Repeated typing of this key cycles through three +different states: auto-refining, no-auto-refining, and no-highlighting +of fine differences. + + +File: ediff.info, Node: Patch and Diff Programs, Next: Merging and diff3, Prev: Refinement of Difference Regions, Up: Customization + +7.8 Patch and Diff Programs +=========================== + +This section describes variables that specify the programs to be used +for applying patches and for computing the main difference regions (not +the fine difference regions): + +`ediff-diff-program' +`ediff-diff3-program' + These variables specify the programs to use to produce differences + and do patching. + +`ediff-diff-options' +`ediff-diff3-options' + These variables specify the options to pass to the above utilities. + + In `ediff-diff-options', it may be useful to specify options such + as `-w' that ignore certain kinds of changes. However, Ediff does + not let you use the option `-c', as it doesn't recognize this + format yet. + +`ediff-coding-system-for-read' + This variable specifies the coding system to use when reading the + output that the programs `diff3' and `diff' send to Emacs. The + default is `raw-text', and this should work fine in Unix and in + most cases under Windows NT/95/98/2000. There are `diff' programs + for which the default option doesn't work under Windows. In such + cases, `raw-text-dos' might work. If not, you will have to + experiment with other coding systems or use GNU diff. + +`ediff-patch-program' + The program to use to apply patches. Since there are certain + incompatibilities between the different versions of the patch + program, the best way to stay out of trouble is to use a + GNU-compatible version. Otherwise, you may have to tune the + values of the variables `ediff-patch-options', + `ediff-backup-specs', and `ediff-backup-extension' as described + below. + +`ediff-patch-options' + Options to pass to `ediff-patch-program'. + + Note: the `-b' and `-z' options should be specified in + `ediff-backup-specs', not in `ediff-patch-options'. + + It is recommended to pass the `-f' option to the patch program, so + it won't ask questions. However, some implementations don't + accept this option, in which case the default value of this + variable should be changed. + +`ediff-backup-extension' + Backup extension used by the patch program. Must be specified, + even if `ediff-backup-specs' is given. + +`ediff-backup-specs' + Backup directives to pass to the patch program. Ediff requires + that the old version of the file (before applying the patch) is + saved in a file named `the-patch-file.extension'. Usually + `extension' is `.orig', but this can be changed by the user, and + may also be system-dependent. Therefore, Ediff needs to know the + backup extension used by the patch program. + + Some versions of the patch program let the user specify `-b + backup-extension'. Other versions only permit `-b', which + (usually) assumes the extension `.orig'. Yet others force you to + use `-z'. + + Note that both `ediff-backup-extension' and `ediff-backup-specs' + must be properly set. If your patch program takes the option + `-b', but not `-b extension', the variable + `ediff-backup-extension' must still be set so Ediff will know + which extension to use. + +`ediff-custom-diff-program' +`ediff-custom-diff-options' + Because Ediff limits the options you may want to pass to the `diff' + program, it partially makes up for this drawback by letting you + save the output from `diff' in your preferred format, which is + specified via the above two variables. + + The output generated by `ediff-custom-diff-program' (which doesn't + even have to be a standard-style `diff'!) is not used by Ediff. + It is provided exclusively so that you can refer to it later, send + it over email, etc. For instance, after reviewing the + differences, you may want to send context differences to a + colleague. Since Ediff ignores the `-c' option in + `ediff-diff-program', you would have to run `diff -c' separately + just to produce the list of differences. Fortunately, + `ediff-custom-diff-program' and `ediff-custom-diff-options' + eliminate this nuisance by keeping a copy of a difference list in + the desired format in a buffer that can be displayed via the + command `D'. + +`ediff-patch-default-directory' + Specifies the default directory to look for patches. + + +*Warning:* Ediff does not support the output format of VMS `diff'. +Instead, make sure you are using some implementation of POSIX `diff', +such as `gnudiff'. + + +File: ediff.info, Node: Merging and diff3, Next: Support for Version Control, Prev: Patch and Diff Programs, Up: Customization + +7.9 Merging and diff3 +===================== + +Ediff supports three-way comparison via the functions `ediff-files3' and +`ediff-buffers3'. The interface is the same as for two-way comparison. +In three-way comparison and merging, Ediff reports if any two difference +regions are identical. For instance, if the current region in buffer A +is the same as the region in buffer C, then the mode line of buffer A +will display `[=diff(C)]' and the mode line of buffer C will display +`[=diff(A)]'. + + Merging is done according to the following algorithm. + + If a difference region in one of the buffers, say B, differs from +the ancestor file while the region in the other buffer, A, doesn't, +then the merge buffer, C, gets B's region. Similarly when buffer A's +region differs from the ancestor and B's doesn't, A's region is used. + + If both regions in buffers A and B differ from the ancestor file, +Ediff chooses the region according to the value of the variable +`ediff-default-variant'. If its value is `default-A' then A's region +is chosen. If it is `default-B' then B's region is chosen. If it is +`combined' then the region in buffer C will look like this: + + <<<<<<< variant A + the difference region from buffer A + >>>>>>> variant B + the difference region from buffer B + ####### Ancestor + the difference region from the ancestor buffer, if available + ======= end + + The above is the default template for the combined region. The user +can customize this template using the variable +`ediff-combination-pattern'. + + The variable `ediff-combination-pattern' specifies the template that +determines how the combined merged region looks like. The template is +represented as a list of the form `(STRING1 Symbol1 STRING2 Symbol2 +STRING3 Symbol3 STRING4)'. The symbols here must be atoms of the form +`A', `B', or `Ancestor'. They determine the order in which the +corresponding difference regions (from buffers A, B, and the ancestor +buffer) are displayed in the merged region of buffer C. The strings in +the template determine the text that separates the aforesaid regions. +The default template is + + ("<<<<<<< variant A" A ">>>>>>> variant B" B + "####### Ancestor" Ancestor "======= end") + +(this is one long line) and the corresponding combined region is shown +above. The order in which the regions are shown (and the separator +strings) can be changed by changing the above template. It is even +possible to add or delete region specifiers in this template (although +the only possibly useful such modification seems to be the deletion of +the ancestor). + + In addition to the state of the difference, Ediff displays the state +of the merge for each region. If a difference came from buffer A by +default (because both regions A and B were different from the ancestor +and `ediff-default-variant' was set to `default-A') then `[=diff(A) +default-A]' is displayed in the mode line. If the difference in buffer +C came, say, from buffer B because the difference region in that buffer +differs from the ancestor, but the region in buffer A does not (if +merging with an ancestor) then `[=diff(B) prefer-B]' is displayed. The +indicators default-A/B and prefer-A/B are inspired by Emerge and have +the same meaning. + + Another indicator of the state of merge is `combined'. It appears +with any difference region in buffer C that was obtained by combining +the difference regions in buffers A and B as explained above. + + In addition to the state of merge and state of difference +indicators, while merging with an ancestor file or buffer, Ediff +informs the user when the current difference region in the (normally +invisible) ancestor buffer is empty via the _AncestorEmpty_ indicator. +This helps determine if the changes made to the original in variants A +and B represent pure insertion or deletion of text: if the mode line +shows _AncestorEmpty_ and the corresponding region in buffers A or B is +not empty, this means that new text was inserted. If this indicator is +not present and the difference regions in buffers A or B are non-empty, +this means that text was modified. Otherwise, the original text was +deleted. + + Although the ancestor buffer is normally invisible, Ediff maintains +difference regions there and advances the current difference region +accordingly. All highlighting of difference regions is provided in the +ancestor buffer, except for the fine differences. Therefore, if +desired, the user can put the ancestor buffer in a separate frame and +watch it there. However, on a TTY, only one frame can be visible at +any given time, and Ediff doesn't support any single-frame window +configuration where all buffers, including the ancestor buffer, would +be visible. However, the ancestor buffer can be displayed by typing +`/' to the control window. (Type `C-l' to hide it again.) + + Note that the state-of-difference indicators `=diff(A)' and +`=diff(B)' above are not redundant, even in the presence of a +state-of-merge indicator. In fact, the two serve different purposes. + + For instance, if the mode line displays `=diff(B) prefer(B)' and you +copy a difference region from buffer A to buffer C then `=diff(B)' will +change to `diff-A' and the mode line will display `=diff(A) prefer-B'. +This indicates that the difference region in buffer C is identical to +that in buffer A, but originally buffer C's region came from buffer B. +This is useful to know because you can recover the original difference +region in buffer C by typing `r'. + + Ediff never changes the state-of-merge indicator, except in response +to the `!' command (see below), in which case the indicator is lost. +On the other hand, the state-of-difference indicator is changed +automatically by the copying/recovery commands, `a', `b', `r', `+'. + + The `!' command loses the information about origins of the regions +in the merge buffer (default-A, prefer-B, or combined). This is because +recomputing differences in this case means running `diff3' on buffers +A, B, and the merge buffer, not on the ancestor buffer. (It makes no +sense to recompute differences using the ancestor file, since in the +merging mode Ediff assumes that you have not edited buffers A and B, +but that you may have edited buffer C, and these changes are to be +preserved.) Since some difference regions may disappear as a result of +editing buffer C and others may arise, there is generally no simple way +to tell where the various regions in the merge buffer came from. + + In three-way comparison, Ediff tries to disregard regions that +consist entirely of white space. For instance, if, say, the current +region in buffer A consists of the white space only (or if it is +empty), Ediff will not take it into account for the purpose of +computing fine differences. The result is that Ediff can provide a +better visual information regarding the actual fine differences in the +non-white regions in buffers B and C. Moreover, if the regions in +buffers B and C differ in the white space only, then a message to this +effect will be displayed. + + In the merge mode, the share of the split between window C (the +window displaying the merge-buffer) and the windows displaying buffers +A and B is controlled by the variable `ediff-merge-window-share'. Its +default value is 0.5. To make the merge-buffer window smaller, reduce +this amount. + + We don't recommend increasing the size of the merge-window to more +than half the frame (i.e., to increase the value of +`ediff-merge-window-share') to more than 0.5, since it would be hard to +see the contents of buffers A and B. + + You can temporarily shrink the merge window to just one line by +typing `s'. This change is temporary, until Ediff finds a reason to +redraw the screen. Typing `s' again restores the original window size. + + With a positive prefix argument, the `s' command will make the merge +window slightly taller. This change is persistent. With ``-'' or with +a negative prefix argument, the command `s' makes the merge window +slightly shorter. This change also persistent. + + Ediff lets you automatically ignore the regions where only one of the +buffers A and B disagrees with the ancestor. To do this, set the +variable `ediff-show-clashes-only' to non-`nil'. + + You can toggle this feature interactively by typing `$$'. + + Note that this variable affects only the show next/previous +difference commands. You can still jump directly to any difference +region directly using the command `j' (with a prefix argument +specifying the difference number). + + The variable `ediff-autostore-merges' controls what happens to the +merge buffer when Ediff quits. If the value is `nil', nothing is done +to the merge buffer--it will be the user's responsibility to save it. +If the value is `t', the user will be asked where to save the buffer +and whether to delete it afterwards. It the value is neither `nil' nor +`t', the merge buffer is saved _only_ if this merge session was invoked +from a group of related Ediff session, such as those that result from +`ediff-merge-directories', `ediff-merge-directory-revisions', etc. +*Note Session Groups::. This behavior is implemented in the function +`ediff-maybe-save-and-delete-merge', which is a hook in +`ediff-quit-merge-hook'. The user can supply a different hook, if +necessary. + + The variable `ediff-autostore-merges' is buffer-local, so it can be +set in a per-buffer manner. Therefore, use `setq-default' to globally +change this variable. + + When merge buffers are saved automatically as directed by +`ediff-autostore-merges', Ediff attaches a prefix to each file, as +specified by the variable `ediff-merge-filename-prefix'. The default is +`merge_', but this can be changed by the user. + + +File: ediff.info, Node: Support for Version Control, Next: Customizing the Mode Line, Prev: Merging and diff3, Up: Customization + +7.10 Support for Version Control +================================ + +Ediff supports version control and lets you compare versions of files +visited by Emacs buffers via the function `ediff-revision'. This +feature is controlled by the following variables: + +`ediff-version-control-package' + A symbol. The default is `vc'. + + If you are like most Emacs users, Ediff will use VC as the version + control package. This is the standard Emacs interface to RCS, + CVS, and SCCS. + + However, if your needs are better served by other interfaces, you + will have to tell Ediff which version control package you are + using, e.g., + (setq ediff-version-control-package 'rcs) + + Apart from the standard `vc.el', Ediff supports three other + interfaces to version control: `rcs.el', `pcl-cvs.el' (recently + renamed pcvs.el), and `generic-sc.el'. The package `rcs.el' is + written by Sebastian Kremer and is available + as + `ftp.cs.buffalo.edu:pub/Emacs/rcs.tar.Z' + `ftp.uni-koeln.de:/pub/gnu/emacs/rcs.tar.Z' + + Ediff's interface to the above packages allows the user to compare +the versions of the current buffer or to merge them (with or without an +ancestor-version). These operations can also be performed on +directories containing files under version control. + + In case of `pcl-cvs.el', Ediff can also be invoked via the function +`run-ediff-from-cvs-buffer'--see the documentation string for this +function. + + +File: ediff.info, Node: Customizing the Mode Line, Next: Miscellaneous, Prev: Support for Version Control, Up: Customization + +7.11 Customizing the Mode Line +============================== + +When Ediff is running, the mode line of `Ediff Control Panel' buffer +shows the current difference number and the total number of difference +regions in the two files. + + The mode line of the buffers being compared displays the type of the +buffer (`A:', `B:', or `C:') and (usually) the file name. Ediff tries +to be intelligent in choosing the mode line buffer identification. In +particular, it works well with the `uniquify.el' and `mode-line.el' +packages (which improve on the default way in which Emacs displays +buffer identification). If you don't like the way Ediff changes the +mode line, you can use `ediff-prepare-buffer-hook' to modify the mode +line. + + +File: ediff.info, Node: Miscellaneous, Next: Notes on Heavy-duty Customization, Prev: Customizing the Mode Line, Up: Customization + +7.12 Miscellaneous +================== + +Here are a few other variables for customizing Ediff: + +`ediff-split-window-function' + Controls the way you want the window be split between file-A and + file-B (and file-C, if applicable). It defaults to the vertical + split (`split-window-vertically', but you can set it to + `split-window-horizontally', if you so wish. Ediff also lets you + switch from vertical to horizontal split and back interactively. + + Note that if Ediff detects that all the buffers it compares are + displayed in separate frames, it assumes that the user wants them + to be so displayed and stops splitting windows. Instead, it + arranges for each buffer to be displayed in a separate frame. You + can switch to the one-frame mode by hiding one of the buffers + A/B/C. + + You can also swap the windows where buffers are displayed by typing + `~'. + +`ediff-merge-split-window-function' + Controls how windows are split between buffers A and B in the + merge mode. This variable is like `ediff-split-window-function', + but it defaults to `split-window-horizontally' instead of + `split-window-vertically'. + +`ediff-make-wide-display-function' + The value is a function to be called to widen the frame for + displaying the Ediff buffers. See the on-line documentation for + `ediff-make-wide-display-function' for details. It is also + recommended to look into the source of the default function + `ediff-make-wide-display'. + + You can toggle wide/regular display by typing `m'. In the wide + display mode, buffers A, B (and C, when applicable) are displayed + in a single frame that is as wide as the entire workstation + screen. This is useful when files are compared side-by-side. By + default, the display is widened without changing its height. + +`ediff-use-last-dir' + Controls the way Ediff presents the default directory when it + prompts the user for files to compare. If `nil', Ediff uses the + default directory of the current buffer when it prompts the user + for file names. Otherwise, it will use the directories it had + previously used for files A, B, or C, respectively. + +`ediff-no-emacs-help-in-control-buffer' + If `t', makes `C-h' behave like the key, i.e., it will move + you back to the previous difference rather than invoking help. + This is useful when, in an xterm window or a text-only terminal, + the Backspace key is bound to `C-h' and is positioned more + conveniently than the key. + +`ediff-toggle-read-only-function' + This variable's value is a function that Ediff uses to toggle the + read-only property in its buffers. + + The default function that Ediff uses simply toggles the read-only + property, unless the file is under version control. For a + checked-in file under version control, Ediff first tries to check + the file out. + +`ediff-make-buffers-readonly-at-startup nil' + If `t', all variant buffers are made read-only at Ediff startup. + +`ediff-keep-variants' + The default is `t', meaning that the buffers being compared or + merged will be preserved when Ediff quits. Setting this to `nil' + causes Ediff to offer the user a chance to delete these buffers + (if they are not modified). Supplying a prefix argument to the + quit command (`q') temporarily reverses the meaning of this + variable. This is convenient when the user prefers one of the + behaviors most of the time, but occasionally needs the other + behavior. + + However, Ediff temporarily resets this variable to `t' if it is + invoked via one of the "buffer" jobs, such as `ediff-buffers'. + This is because it is all too easy to loose day's work otherwise. + Besides, in a "buffer" job, the variant buffers have already been + loaded prior to starting Ediff, so Ediff just preserves status quo + here. + + Using `ediff-cleanup-hook', one can make Ediff delete the variants + unconditionally (e.g., by making `ediff-janitor' into one of these + hooks). + +`ediff-grab-mouse' + Default is `t'. Normally, Ediff grabs mouse and puts it in its + control frame. This is useful since the user can be sure that + when he needs to type an Ediff command the focus will be in an + appropriate Ediff's frame. However, some users prefer to move the + mouse by themselves. The above variable, if set to `maybe', will + prevent Ediff from grabbing the mouse in many situations, usually + after commands that may take more time than usual. In other + situation, Ediff will continue grabbing the mouse and putting it + where it believes is appropriate. If the value is `nil', then + mouse is entirely user's responsibility. Try different settings + and see which one is for you. + + +File: ediff.info, Node: Notes on Heavy-duty Customization, Prev: Miscellaneous, Up: Customization + +7.13 Notes on Heavy-duty Customization +====================================== + +Some users need to customize Ediff in rather sophisticated ways, which +requires different defaults for different kinds of files (e.g., SGML, +etc.). Ediff supports this kind of customization in several ways. +First, most customization variables are buffer-local. Those that +aren't are usually accessible from within Ediff Control Panel, so one +can make them local to the panel by calling make-local-variable from +within `ediff-startup-hook'. + + Second, the function `ediff-setup' accepts an optional sixth +argument which has the form `((VAR-NAME-1 . VAL-1) (VAR-NAME-2 . VAL-2) +...)'. The function `ediff-setup' sets the variables in the list to +the respective values, locally in the Ediff control buffer. This is an +easy way to throw in custom variables (which usually should be +buffer-local) that can then be tested in various hooks. + + Make sure the variable `ediff-job-name' and `ediff-word-mode' are set +properly in this case, as some things in Ediff depend on this. + + Finally, if you want custom-tailored help messages, you can set the +variables `ediff-brief-help-message-function' and +`ediff-long-help-message-function' to functions that return help +strings. + + When customizing Ediff, some other variables are useful, although +they are not user-definable. They are local to the Ediff control +buffer, so this buffer must be current when you access these variables. +The control buffer is accessible via the variable +`ediff-control-buffer', which is also local to that buffer. It is +usually used for checking if the current buffer is also the control +buffer. + + Other variables of interest are: +`ediff-buffer-A' + The first of the data buffers being compared. + +`ediff-buffer-B' + The second of the data buffers being compared. + +`ediff-buffer-C' + In three-way comparisons, this is the third buffer being compared. + In merging, this is the merge buffer. In two-way comparison, this + variable is `nil'. + +`ediff-window-A' + The window displaying buffer A. If buffer A is not visible, this + variable is `nil' or it may be a dead window. + +`ediff-window-B' + The window displaying buffer B. + +`ediff-window-C' + The window displaying buffer C, if any. + +`ediff-control-frame' + A dedicated frame displaying the control buffer, if it exists. It + is non-`nil' only if Ediff uses the multiframe display, i.e., when + the control buffer is in its own frame. + + +File: ediff.info, Node: Credits, Next: Index, Prev: Customization, Up: Top + +8 Credits +********* + +Ediff was written by Michael Kifer . It was +inspired by emerge.el written by Dale R. Worley . An +idea due to Boris Goldowsky made it possible +to highlight fine differences in Ediff buffers. Alastair Burt + ported Ediff to XEmacs, Eric Freudenthal + made it work with VC, Marc Paquette + wrote the toolbar support package for Ediff, and +Hrvoje Niksic adapted it to the Emacs +customization package. + + Many people provided help with bug reports, feature suggestions, and +advice. Without them, Ediff would not be nearly as useful as it is +today. Here is a hopefully full list of contributors: + + Adrian Aichner (aichner@ecf.teradyne.com), + Drew Adams (drew.adams@oracle.com), + Steve Baur (steve@xemacs.org), + Neal Becker (neal@ctd.comsat.com), + E. Jay Berkenbilt (ejb@ql.org), + Alastair Burt (burt@dfki.uni-kl.de), + Paul Bibilo (peb@delcam.co.uk), + Kevin Broadey (KevinB@bartley.demon.co.uk), + Harald Boegeholz (hwb@machnix.mathematik.uni-stuttgart.de), + Bradley A. Bosch (brad@lachman.com), + Michael D. Carney (carney@ltx-tr.com), + Jin S. Choi (jin@atype.com), + Scott Cummings (cummings@adc.com), + Albert Dvornik (bert@mit.edu), + Eric Eide (eeide@asylum.cs.utah.edu), + Paul Eggert (eggert@twinsun.com), + Urban Engberg (ue@cci.dk), + Kevin Esler (esler@ch.hp.com), + Robert Estes (estes@ece.ucdavis.edu), + Jay Finger (jayf@microsoft.com), + Xavier Fornari (xavier@europe.cma.fr), + Eric Freudenthal (freudent@jan.ultra.nyu.edu), + Job Ganzevoort (Job.Ganzevoort@cwi.nl), + Felix Heinrich Gatzemeier (felix.g@tzemeier.info), + Boris Goldowsky (boris@cs.rochester.edu), + Allan Gottlieb (gottlieb@allan.ultra.nyu.edu), + Aaron Gross (aaron@bfr.co.il), + Thorbjoern Hansen (thorbjoern.hansen@mchp.siemens.de), + Marcus Harnisch (marcus_harnisch@mint-tech.com), + Steven E. Harris (seh@panix.com), + Aaron S. Hawley (Aaron.Hawley@uvm.edu), + Xiaoli Huang (hxl@epic.com), + Andreas Jaeger (aj@suse.de), + Lars Magne Ingebrigtsen (larsi@ifi.uio.no), + Larry Gouge (larry@itginc.com), + Karl Heuer (kwzh@gnu.org), + (irvine@lks.csi.com), + (jaffe@chipmunk.cita.utoronto.ca), + David Karr (dkarr@nmo.gtegsc.com), + Norbert Kiesel (norbert@i3.informatik.rwth-aachen.de), + Leigh L Klotz (klotz@adoc.xerox.com), + Fritz Knabe (Fritz.Knabe@ecrc.de), + Heinz Knutzen (hk@informatik.uni-kiel.d400.de), + Andrew Koenig (ark@research.att.com), + Hannu Koivisto (azure@iki.fi), + Ken Laprade (laprade@dw3f.ess.harris.com), + Will C Lauer (wcl@cadre.com), + Richard Levitte (levitte@e.kth.se), + Mike Long (mike.long@analog.com), + Dave Love (d.love@dl.ac.uk), + Martin Maechler (maechler@stat.math.ethz.ch), + Simon Marshall (simon@gnu.org), + Paul C. Meuse (pmeuse@delcomsys.com), + Richard Mlynarik (mly@adoc.xerox.com), + Stefan Monnier (monnier@cs.yale.edu), + Chris Murphy (murphycm@sun.aston.ac.uk), + Erik Naggum (erik@naggum.no), + Eyvind Ness (Eyvind.Ness@hrp.no), + Ray Nickson (nickson@cs.uq.oz.au), + Dan Nicolaescu (dann@ics.uci.edu), + David Petchey (petchey_david@jpmorgan.com), + Benjamin Pierce (benjamin.pierce@cl.cam.ac.uk), + Francois Pinard (pinard@iro.umontreal.ca), + Tibor Polgar (tlp00@spg.amdahl.com), + David Prince (dave0d@fegs.co.uk), + Paul Raines (raines@slac.stanford.edu), + Stefan Reicher (xsteve@riic.at), + Charles Rich (rich@merl.com), + Bill Richter (richter@math.nwu.edu), + C.S. Roberson (roberson@aur.alcatel.com), + Kevin Rodgers (kevin.rodgers@ihs.com), + Sandy Rutherford (sandy@ibm550.sissa.it), + Heribert Schuetz (schuetz@ecrc.de), + Andy Scott (ascott@pcocd2.intel.com), + Axel Seibert (axel@tumbolia.ppp.informatik.uni-muenchen.de), + Vin Shelton (acs@xemacs.org), + Scott O. Sherman (Scott.Sherman@mci.com), + Richard Stallman (rms@gnu.org), + Richard Stanton (stanton@haas.berkeley.edu), + Sam Steingold (sds@goems.com), + Ake Stenhoff (etxaksf@aom.ericsson.se), + Stig (stig@hackvan.com), + Peter Stout (Peter_Stout@cs.cmu.edu), + Chuck Thompson (cthomp@cs.uiuc.edu), + Ray Tomlinson (tomlinso@bbn.com), + Raymond Toy (toy@rtp.ericsson.se), + Stephen J. Turnbull (stephen@xemacs.org), + Jan Vroonhof (vroonhof@math.ethz.ch), + Colin Walters (walters@cis.ohio-state.edu), + Philippe Waroquiers (philippe.waroquiers@eurocontrol.be), + Klaus Weber (gizmo@zork.north.de), + Ben Wing (ben@xemacs.org), + Tom Wurgler (twurgler@goodyear.com), + Steve Youngs (youngs@xemacs.org), + Ilya Zakharevich (ilya@math.ohio-state.edu), + Eli Zaretskii (eliz@is.elta.co.il) + + +File: ediff.info, Node: Index, Prev: Credits, Up: Top + +Index +***** + +[index] +* Menu: + +* !: Quick Help Commands. (line 146) +* ##: Quick Help Commands. (line 223) +* #c: Quick Help Commands. (line 231) +* #f: Quick Help Commands. (line 238) +* #h: Quick Help Commands. (line 238) +* $$: Quick Help Commands. (line 337) +* $*: Quick Help Commands. (line 357) +* %: Quick Help Commands. (line 327) +* &: Quick Help Commands. (line 376) +* *: Quick Help Commands. (line 153) +* +: Quick Help Commands. (line 416) +* /: Quick Help Commands. (line 373) +* <: Quick Help Commands. (line 26) +* =: Quick Help Commands. (line 421) +* >: Quick Help Commands. (line 29) +* ?: Quick Help Commands. (line 7) +* @: Quick Help Commands. (line 181) +* A: Quick Help Commands. (line 260) +* a: Quick Help Commands. (line 51) +* ab: Quick Help Commands. (line 71) +* ac: Quick Help Commands. (line 78) +* B: Quick Help Commands. (line 265) +* b: Quick Help Commands. (line 62) +* ba: Quick Help Commands. (line 83) +* bc: Quick Help Commands. (line 88) +* C: Quick Help Commands. (line 269) +* C-l: Quick Help Commands. (line 332) +* ca: Quick Help Commands. (line 92) +* cb: Quick Help Commands. (line 96) +* Comparing files and buffers: Introduction. (line 6) +* D: Quick Help Commands. (line 282) +* DEL: Quick Help Commands. (line 101) +* Directory difference buffer: Session Groups. (line 36) +* E: Quick Help Commands. (line 14) +* ediff: Major Entry Points. (line 23) +* ediff-after-flag-eol: Highlighting Difference Regions. + (line 13) +* ediff-after-flag-mol: Highlighting Difference Regions. + (line 13) +* ediff-after-session-group-setup-hook: Hooks. (line 112) +* ediff-after-setup-control-frame-hook: Hooks. (line 69) +* ediff-after-setup-windows-hook: Hooks. (line 24) +* ediff-auto-refine: Refinement of Difference Regions. + (line 11) +* ediff-auto-refine-limit: Refinement of Difference Regions. + (line 30) +* ediff-autostore-merges <1>: Merging and diff3. (line 166) +* ediff-autostore-merges <2>: Hooks. (line 62) +* ediff-autostore-merges: Session Groups. (line 64) +* ediff-backup: Major Entry Points. (line 26) +* ediff-before-flag-bol: Highlighting Difference Regions. + (line 13) +* ediff-before-flag-mol: Highlighting Difference Regions. + (line 13) +* ediff-before-session-group-setup-hook: Hooks. (line 107) +* ediff-before-setup-control-frame-hook: Hooks. (line 69) +* ediff-before-setup-hook: Hooks. (line 12) +* ediff-before-setup-windows-hook: Hooks. (line 24) +* ediff-brief-help-message-function: Notes on Heavy-duty Customization. + (line 27) +* ediff-buffers: Major Entry Points. (line 31) +* ediff-buffers3: Major Entry Points. (line 38) +* ediff-cleanup-hook: Hooks. (line 49) +* ediff-coding-system-for-read: Patch and Diff Programs. + (line 25) +* ediff-combination-pattern: Merging and diff3. (line 39) +* ediff-control-buffer: Quick Help Customization. + (line 6) +* ediff-control-frame-parameters: Window and Frame Configuration. + (line 35) +* ediff-control-frame-position-function: Window and Frame Configuration. + (line 48) +* ediff-control-frame-upward-shift: Window and Frame Configuration. + (line 70) +* ediff-current-diff-face-A: Highlighting Difference Regions. + (line 22) +* ediff-current-diff-face-B: Highlighting Difference Regions. + (line 22) +* ediff-current-diff-face-C: Highlighting Difference Regions. + (line 22) +* ediff-custom-diff-options: Patch and Diff Programs. + (line 78) +* ediff-custom-diff-program: Patch and Diff Programs. + (line 78) +* ediff-default-variant: Merging and diff3. (line 21) +* ediff-diff-options: Patch and Diff Programs. + (line 17) +* ediff-diff-program <1>: Patch and Diff Programs. + (line 12) +* ediff-diff-program: Refinement of Difference Regions. + (line 42) +* ediff-diff3-options: Patch and Diff Programs. + (line 17) +* ediff-diff3-program: Patch and Diff Programs. + (line 12) +* ediff-directories: Major Entry Points. (line 42) +* ediff-directories3: Major Entry Points. (line 46) +* ediff-directory-revisions: Major Entry Points. (line 50) +* ediff-display-help-hook: Hooks. (line 93) +* ediff-documentation: Major Entry Points. (line 165) +* ediff-even-diff-face-A: Highlighting Difference Regions. + (line 40) +* ediff-even-diff-face-B: Highlighting Difference Regions. + (line 40) +* ediff-even-diff-face-C: Highlighting Difference Regions. + (line 40) +* ediff-files: Major Entry Points. (line 23) +* ediff-files3: Major Entry Points. (line 35) +* ediff-fine-diff-face-A: Highlighting Difference Regions. + (line 31) +* ediff-fine-diff-face-B: Highlighting Difference Regions. + (line 31) +* ediff-fine-diff-face-C: Highlighting Difference Regions. + (line 31) +* ediff-force-faces: Highlighting Difference Regions. + (line 47) +* ediff-forward-word: Refinement of Difference Regions. + (line 42) +* ediff-forward-word-function: Refinement of Difference Regions. + (line 38) +* ediff-grab-mouse: Miscellaneous. (line 92) +* ediff-help-message: Quick Help Customization. + (line 6) +* ediff-highlight-all-diffs: Highlighting Difference Regions. + (line 53) +* ediff-ignore-case <1>: Selective Browsing. (line 87) +* ediff-ignore-case: Quick Help Commands. (line 231) +* ediff-ignore-case-option <1>: Selective Browsing. (line 87) +* ediff-ignore-case-option: Quick Help Commands. (line 231) +* ediff-ignore-case-option3 <1>: Selective Browsing. (line 87) +* ediff-ignore-case-option3: Quick Help Commands. (line 231) +* ediff-ignore-similar-regions: Selective Browsing. (line 70) +* ediff-janitor: Hooks. (line 54) +* ediff-job-name: Notes on Heavy-duty Customization. + (line 27) +* ediff-keep-variants: Miscellaneous. (line 71) +* ediff-keymap-setup-hook: Hooks. (line 16) +* ediff-load-hook: Hooks. (line 9) +* ediff-long-help-message-function: Notes on Heavy-duty Customization. + (line 27) +* ediff-make-buffers-readonly-at-startup: Miscellaneous. (line 68) +* ediff-make-frame-position: Window and Frame Configuration. + (line 55) +* ediff-make-wide-display-function: Miscellaneous. (line 32) +* ediff-maybe-save-and-delete-merge <1>: Merging and diff3. (line 166) +* ediff-maybe-save-and-delete-merge: Hooks. (line 62) +* ediff-merge: Major Entry Points. (line 136) +* ediff-merge-buffers: Major Entry Points. (line 143) +* ediff-merge-buffers-with-ancestor: Major Entry Points. (line 146) +* ediff-merge-directories: Major Entry Points. (line 150) +* ediff-merge-directories-with-ancestor: Major Entry Points. (line 154) +* ediff-merge-directory-revisions: Major Entry Points. (line 55) +* ediff-merge-directory-revisions-with-ancestor: Major Entry Points. + (line 60) +* ediff-merge-filename-prefix: Merging and diff3. (line 183) +* ediff-merge-files: Major Entry Points. (line 136) +* ediff-merge-files-with-ancestor: Major Entry Points. (line 140) +* ediff-merge-revisions: Major Entry Points. (line 159) +* ediff-merge-revisions-with-ancestor: Major Entry Points. (line 162) +* ediff-merge-split-window-function: Miscellaneous. (line 26) +* ediff-merge-window-share: Merging and diff3. (line 135) +* ediff-merge-with-ancestor: Major Entry Points. (line 140) +* ediff-meta-buffer-keymap-setup-hook: Hooks. (line 119) +* ediff-meta-buffer-map: Hooks. (line 119) +* ediff-mode-hook: Hooks. (line 98) +* ediff-mode-map: Hooks. (line 16) +* ediff-narrow-control-frame-leftward-shift: Window and Frame Configuration. + (line 60) +* ediff-no-emacs-help-in-control-buffer: Miscellaneous. (line 52) +* ediff-odd-diff-face-A: Highlighting Difference Regions. + (line 40) +* ediff-odd-diff-face-B: Highlighting Difference Regions. + (line 40) +* ediff-odd-diff-face-C: Highlighting Difference Regions. + (line 40) +* ediff-patch-buffer: Major Entry Points. (line 119) +* ediff-patch-default-directory: Patch and Diff Programs. + (line 97) +* ediff-patch-file: Major Entry Points. (line 88) +* ediff-patch-options: Patch and Diff Programs. + (line 17) +* ediff-patch-program: Patch and Diff Programs. + (line 12) +* ediff-prefer-iconified-control-frame: Window and Frame Configuration. + (line 74) +* ediff-prepare-buffer-hook <1>: Customizing the Mode Line. + (line 17) +* ediff-prepare-buffer-hook: Hooks. (line 89) +* ediff-profile: Other Session Commands. + (line 56) +* ediff-quit-hook: Hooks. (line 31) +* ediff-quit-merge-hook <1>: Merging and diff3. (line 166) +* ediff-quit-merge-hook: Hooks. (line 62) +* ediff-quit-session-group-hook: Hooks. (line 116) +* ediff-quit-widened: Narrowing. (line 27) +* ediff-regions-linewise: Major Entry Points. (line 79) +* ediff-regions-wordwise: Major Entry Points. (line 71) +* ediff-registry-setup-hook: Hooks. (line 103) +* ediff-revert-buffers-then-recompute-diffs: Other Session Commands. + (line 46) +* ediff-revision: Major Entry Points. (line 83) +* ediff-save-buffer: Patch and Diff Programs. + (line 78) +* ediff-select-hook: Hooks. (line 82) +* ediff-setup: Notes on Heavy-duty Customization. + (line 27) +* ediff-setup-windows: Window and Frame Configuration. + (line 85) +* ediff-setup-windows-multiframe: Window and Frame Configuration. + (line 103) +* ediff-setup-windows-plain: Window and Frame Configuration. + (line 103) +* ediff-show-clashes-only: Merging and diff3. (line 155) +* ediff-show-registry: Other Session Commands. + (line 11) +* ediff-split-window-function: Miscellaneous. (line 9) +* ediff-start-narrowed: Narrowing. (line 21) +* ediff-startup-hook <1>: Notes on Heavy-duty Customization. + (line 27) +* ediff-startup-hook <2>: Quick Help Customization. + (line 6) +* ediff-startup-hook: Hooks. (line 79) +* ediff-suspend-hook: Hooks. (line 31) +* ediff-toggle-multiframe <1>: Window and Frame Configuration. + (line 103) +* ediff-toggle-multiframe: Other Session Commands. + (line 21) +* ediff-toggle-read-only-function: Miscellaneous. (line 59) +* ediff-toggle-use-toolbar: Other Session Commands. + (line 33) +* ediff-unselect-hook: Hooks. (line 85) +* ediff-use-last-dir <1>: Miscellaneous. (line 45) +* ediff-use-last-dir: Major Entry Points. (line 188) +* ediff-use-long-help-message: Quick Help Customization. + (line 6) +* ediff-use-toolbar-p: Other Session Commands. + (line 40) +* ediff-version-control-package: Support for Version Control. + (line 11) +* ediff-wide-control-frame-rightward-shift: Window and Frame Configuration. + (line 65) +* ediff-window-setup-function: Window and Frame Configuration. + (line 96) +* ediff-windows-linewise: Major Entry Points. (line 68) +* ediff-windows-wordwise: Major Entry Points. (line 65) +* ediff-word-1: Refinement of Difference Regions. + (line 54) +* ediff-word-2: Refinement of Difference Regions. + (line 54) +* ediff-word-3: Refinement of Difference Regions. + (line 54) +* ediff-word-4: Refinement of Difference Regions. + (line 54) +* ediff-word-mode: Notes on Heavy-duty Customization. + (line 27) +* ediff3: Major Entry Points. (line 35) +* edir-merge-revisions: Major Entry Points. (line 55) +* edir-merge-revisions-with-ancestor: Major Entry Points. (line 60) +* edir-revisions: Major Entry Points. (line 50) +* edirs: Major Entry Points. (line 42) +* edirs-merge: Major Entry Points. (line 150) +* edirs-merge-with-ancestor: Major Entry Points. (line 154) +* edirs3: Major Entry Points. (line 46) +* epatch: Major Entry Points. (line 88) +* epatch-buffer: Major Entry Points. (line 119) +* eregistry: Other Session Commands. + (line 11) +* Finding differences: Introduction. (line 6) +* G: Quick Help Commands. (line 10) +* ga: Quick Help Commands. (line 117) +* gb: Quick Help Commands. (line 129) +* gc: Quick Help Commands. (line 136) +* generic-sc.el: Support for Version Control. + (line 29) +* h: Quick Help Commands. (line 191) +* i: Quick Help Commands. (line 279) +* j: Quick Help Commands. (line 110) +* M: Quick Help Commands. (line 306) +* m: Quick Help Commands. (line 169) +* Merging files and buffers: Introduction. (line 6) +* mode-line.el: Customizing the Mode Line. + (line 17) +* Multi-file patches: Session Groups. (line 81) +* n: Quick Help Commands. (line 105) +* p: Quick Help Commands. (line 101) +* Patching files and buffers: Introduction. (line 6) +* pcl-cvs.el: Support for Version Control. + (line 29) +* q: Quick Help Commands. (line 321) +* R: Quick Help Commands. (line 290) +* r: Quick Help Commands. (line 197) +* ra: Quick Help Commands. (line 205) +* rb: Quick Help Commands. (line 211) +* rc: Quick Help Commands. (line 217) +* rcs.el: Support for Version Control. + (line 29) +* s: Quick Help Commands. (line 396) +* SPC: Quick Help Commands. (line 105) +* uniquify.el: Customizing the Mode Line. + (line 17) +* V: Quick Help Commands. (line 23) +* v: Quick Help Commands. (line 19) +* vc.el: Support for Version Control. + (line 29) +* wa: Quick Help Commands. (line 41) +* wb: Quick Help Commands. (line 44) +* wc: Quick Help Commands. (line 47) +* wd: Quick Help Commands. (line 32) +* z: Quick Help Commands. (line 311) +* |: Quick Help Commands. (line 175) +* ~: Quick Help Commands. (line 274) + + + +Tag Table: +Node: Top1411 +Node: Introduction2015 +Node: Major Entry Points4410 +Node: Session Commands14323 +Node: Quick Help Commands15846 +Node: Other Session Commands34301 +Node: Registry of Ediff Sessions37106 +Node: Session Groups38667 +Node: Remote and Compressed Files44837 +Node: Customization46074 +Node: Hooks48032 +Node: Quick Help Customization53336 +Node: Window and Frame Configuration54352 +Node: Selective Browsing60320 +Node: Highlighting Difference Regions65464 +Node: Narrowing70211 +Node: Refinement of Difference Regions71494 +Node: Patch and Diff Programs74434 +Node: Merging and diff379006 +Node: Support for Version Control88814 +Node: Customizing the Mode Line90444 +Node: Miscellaneous91303 +Node: Notes on Heavy-duty Customization96273 +Node: Credits98863 +Node: Index103819 + +End Tag Table diff --git a/xemacs-packages/info/edit-utils.info b/xemacs-packages/info/edit-utils.info new file mode 100644 index 00000000..acb73539 --- /dev/null +++ b/xemacs-packages/info/edit-utils.info @@ -0,0 +1,3987 @@ +This is edit-utils.info, produced by makeinfo version 4.7 from +edit-utils.texi. + +INFO-DIR-SECTION XEmacs Editor +START-INFO-DIR-ENTRY +* Edit Utilities: (edit-utils). Editing Utilities for XEmacs. +END-INFO-DIR-ENTRY + + This manual is part of XEmacs. + + XEmacs 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. + + XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + + +File: edit-utils.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) + +1 The Editing Utilities Package +******************************* + +This Info file contains the manual for the Editing Utilities package. + +The node name for each entry in the menu is the name of the elisp file +containing the code that implements the functionality described. It is +highly recommended that you briefly peruse the elisp source code since +it can provide valuable information on usage and technique. This can +easily be done by typing `C-x 4 l RET' where is +the name of the elisp file to be loaded. + +* Menu: + +* Copying:: Why this manual is GPL, and what that means + +Buffer and Window Management +* compare-w:: Comparing Windows +* detached-minibuf:: Detached Minibuffers +* iswitchb:: Convenient Buffer Switching +* permanent-buffers:: Permanent Buffers +* rsz-minibuf:: Self-Resizing Minibuffer +* search-buffers:: Searching Many Buffers +* uniquify:: Meaningful Unique Names +* winring:: Window Configuration Rings +* autorevert:: Reverting Buffers + +Editing Help +* foldout:: Folding Extensions for Outline-Mode +* func-menu:: Jump to a Function Within a Buffer. +* id-select:: Select Syntax-Driven Regions in a Buffer +* outl-mouse:: Outline-Mode Mouse Commands +* page-ext:: Extended Page Handling Commands +* power-macros:: Power Macros - Keyboard Macros Made Easy +* redo:: Redo/Undo System +* scroll-in-place:: Scrolling In Place +* setnu:: VI-style Line Number Mode +* vertical-mode:: Vertical Mode - Editing of Vertical Text +* align:: Align Text to a Specific Column, By Regexp +* allout:: Extensive Outline Mode +* narrow-stack:: Extending the built-in narrowing functions + +File Management +* backup-dir:: Specify Directories to be Used for Backup Files + +Session Management +* bookmark:: Create annotated bookmarks +* desktop:: Save Partial Status of Emacs When Killed +* recent-files:: Recent File Navigation +* resume:: Resuming a Suspended Emacs Job +* saveconf:: Save Buffer/Window Configuration Between Sessions +* savehist:: Save Minibuffer History +* saveplace:: Automatically Save Place in Files +* where-was-i-db:: Keep Persistent State in Visited Files + +Abbreviations +* completion:: Completion +* dabbrev:: Dynamic Abbreviations +* hippie-exp:: Hippie Expand +* icomplete:: Interactive Minibuffer Completion +* tempo:: Flexible Template Insertion + +Display, Faces, and Highlighting: +* avoid:: Move Mouse Pointer Out of the Way of Editing +* blink-cursor:: Blinking Cursor +* fast-lock:: Speeding Up Font Lock Mode +* lazy-lock:: Lazy Demand-Driven Fontification +* lazy-shot:: Another Lazy Demand-Driven Fontification +* mic-paren:: Advanced Highlighting of Matching Parentheses +* paren:: Highlight (Un)matching Parens and Whole Expressions +* shell-font:: Decorate a Shell Buffer With Fonts +* highline:: Highlight the Current Line in the Buffer + +Low-Level Editing Hacks: +* after-save-commands:: Hooks Invoked After Saving a File +* atomic-extents:: Indivisible Blocks of Text +* array:: Table and Array Editor + +Menu and Toolbar Support: +* floating-toolbar:: Floating Toolbar +* The Toolbar Utilities:: Creating and Managing Toolbars and Buttons. + +Miscellaneous: +* flow-ctrl:: Flow Control +* makesum:: Generate Summary of All Key Binding +* man:: Browse UNIX manual pages + +Undocumented: +* abbrevlist:: Abbreviation List +* file-part:: Treat a Section of a Buffer as a Separate File +* info-look:: Major-Mode-Sensitive Info Index Lookup Facility +* live-icon:: Make Frame Icons Represent Current Frame Contents +* mode-motion+:: Per Mode/Buffer Mouse Tracking With Highlighting +* popper:: Shrink-Wrapped Temporary Windows +* reportmail:: Display Time and Load in Mode Line +* balloon-help:: Balloon Help and Tooltips +* blink-paren:: Blinking Parentheses +* edit-faces:: Face Editor +* lispm-fonts:: lispm-fonts +* big-menubar:: Big Menubar +* tree-menu:: tree-menu.el + +Appendices: +* XEmacs License:: The GNU General Public License + + +File: edit-utils.info, Node: Copying, Next: compare-w, Prev: Top, Up: Top + +2 Copying +********* + +This document may be redistributed, verbatim or in modified form, under +the terms of the GNU General Public License, version 2 or any later +version. The same terms apply to the libraries it documents. A copy +of the General Public License is provided as an Appendix. + + Most XEmacs documentation has its own license, which is an ancestor +of the GNU Free Documentation License ("FDL"), and whose terms are +quite similar to those imposed by GNU on Emacs documentation. Why is +this manual licensed differently (under the GNU General Public License, +or "GPL"), and why does it have to be distributed separately from the +XEmacs User's Guide and the XEmacs Lisp Reference Manual? + + Taking the second question first, XEmacs is "community-owned" +software. That is, unlike GNU Emacs, there is no monopoly copyright +holder. Many of us, including the original Lucid authors, have +contributed our copyrights to the Free Software Foundation (FSF), and of +course much content is derived from GNU Emacs, and therefore is held by +the FSF. Another large chunk is held by Sun Microsystems, and a few +individual authors hold copyright to thousands of lines each. But many +individuals hold copyright to only a few dozen lines. Like the Linux +kernel, copyright ownership is distributed throughout a community. + + However, its license is "copyleft," _i.e._, it _requires_ that you +redistribute it under terms _identical_ to those under which you +received it, unless you have explicit permission of the copyright +holder. Because of the multiple owners, determining the ownership of +any given part of XEmacs is tedious, and perhaps impossible. For +practical purposes, then, the license of any substantial chunk of +existing XEmacs content cannot be changed, except to a later version of +the GPL, for those parts under GPL. (That is due to the _explicit_ +permission to change to a later version of the GPL, present in every +file of XEmacs.) + + Unfortunately, this severe restriction means that the GPL, FDL, and +the XEmacs documentation license ("XDL") are _mutually incompatible_. +That is, content licensed under any of the GPL, FDL, or XDL _may not_ +be mixed with content licensed under either of the other two without +changing the license of some of the content. But this requires +permission of the copyright holder, which is often difficult or +impossible to get. + + For example, you _may not_ take comments or docstrings from XEmacs +code and add them to the Lispref to mend a gap in the latter's coverage. +You _may not_ copy text from the Lispref into docstrings in the code. +And you _may not_ copy text from the GNU Emacs Lisp Reference to the +XEmacs Lisp Reference Manual. (In this case it is at least trivial to +ask permission, although it is rather unclear whether it would be +granted.) + + In fact, parts of this document were derived by copying from XEmacs +code under the GPL, without any further permission from the authors. +Thus, this document must be distributed under the GPL, as a "volume" +separate from the XEmacs documentation under the XDL. Note that the +"mere aggregation" clauses allow us to distribute in the same tarball. +But incorporating it as a node in the Lispref is prohibited, even if +done by inclusion. + + A bit of advocacy: + + If you look carefully at the additional restrictions imposed by the +soi-disant "free" documentation licenses, you discover that they are +simply proprietary restrictions guaranteeing a certain amount of +_unpaid_ political advertising to the Free Software Foundation and GNU +Project (and in the case of the FDL, this is extended to commercial +advertising by authors of original or derived works). Whether this is +"ethically justified" or not is a difficult question. What is certain +is that there is little social benefit to these terms (since the license +documents themselves contain the advocacy and must be included with any +distribution). + + I conclude it makes sense for XEmacs to reduce its restrictions, +where possible, to the "least common denominator," the GNU General +Public License. + + +File: edit-utils.info, Node: compare-w, Next: detached-minibuf, Prev: Copying, Up: Top + +3 Comparing Windows +******************* + +This package provides one entry point, compare-windows. It compares +text starting from point in two adjacent windows, advancing point until +it finds a difference. There are variables to permit ignoring of +whitespace differences, or case differences, or both. + + +File: edit-utils.info, Node: detached-minibuf, Next: iswitchb, Prev: compare-w, Up: Top + +4 Detached Minibuffers +********************** + +This package creates a standalone minibuffer in its own frame. + + To configure this package, type: + + M-x customize-group RET detached-minibuf RET + + +File: edit-utils.info, Node: iswitchb, Next: permanent-buffers, Prev: detached-minibuf, Up: Top + +5 Convenient Buffer Switching +***************************** + +With this package installed, as you type in a substring, the list of +buffers currently matching the substring are displayed as you type. +The list is ordered so that the most recent buffers visited come at the +start of the list. The buffer at the start of the list will be the one +visited when you press return. By typing more of the substring, the +list is narrowed down so that gradually the buffer you want will be at +the top of the list. Alternatively, you can use `C-s' and `C-r' to +rotate buffer names in the list until the one you want is at the top of +the list. Completion is also available so that you can see what is +common to all of the matching buffers as you type. + + For example, let's say we have two buffers called "123456" and +"123", with "123456" the most recent. When I use `iswitchb', I first of +all get presented with the list of all the buffers + + `iswitch {123456,123}' + + If I then press `2': + + `iswitch 2[3]{123456,123}' + + The list in {} are the matching buffers, most recent first (buffers +visible in the current frame are put at the end of the list by +default). At any time I can select the item at the head of the list by +pressing `RET'. I can also bring the put the first element at the end +of the list by pressing `C-s', or put the last element at the head of +the list by pressing `C-r'. The item in [] indicates what can be added +to my input by pressing `TAB'. In this case, I will get `3' added to +my input. So, press `TAB': + + `iswitch 23{123456,123}' + + At this point, I still have two matching buffers. If I want the +first buffer in the list, I simply press `RET'. If I wanted the second +in the list, I could press `C-s' to move it to the top of the list and +then `RET' to select it. + + However, If I type `4', I only have one match left: + + `iswitch 234[123456] [Matched]' + + Since there is only one matching buffer left, it is given in `[]' +and we see the text `[Matched]' afterwards. I can now press `TAB' or +`RET' to go to that buffer. + + If however, I now type `a': + + `iswitch 234a [No match]' + + There are no matching buffers. If I press `RET' or `TAB', I can be +prompted to create a new buffer called "234a". + + Of course, where this function comes in really useful is when you +can specify the buffer using only a few keystrokes. In the above +example, the quickest way to get to the "123456" buffer would be just +to type `4' and then `RET' (assuming there isn't any newer buffer with +"4" in its name). + + To see a full list of all matching buffers in a separate buffer, hit +`?' or press `TAB' when there are no further completions to the +substring. Repeated `TAB' presses will scroll you through this +separate buffer. + + The buffer at the head of the list can be killed by pressing `C-k'. +If the buffer needs saving, you will be queried before the buffer is +killed. + + If you find that the file you are after is not in a buffer, you can +press `C-x C-f' to immediately drop into find-file. + + To see the doc string of iswitchb for full keybindings and features, +type: + + M-x describe-function RET iswitchb + +* Menu: + +* Customization: iswitchb-cust. +* Changing the Display:: +* Regexp Matching:: +* Replacement for read-buffer:: + + +File: edit-utils.info, Node: iswitchb-cust, Next: Changing the Display, Prev: iswitchb, Up: iswitchb + +5.1 Customization +================= + +To configure the package, type: + + M-x customize-group RET iswitchb RET + + To install this package on the default keys used for buffer +switching, type: + + M-x iswitchb-default-keybindings RET + + To modify the default keybindings, use the hook provided. For +example, the following code can be added to your initialization file: + + (add-hook 'iswitchb-define-mode-map-hook 'iswitchb-my-keys) + + (defun iswitchb-my-keys () + "Add my keybindings for iswitchb." + (define-key iswitchb-mode-map " " 'iswitchb-next-match) + ) + + +File: edit-utils.info, Node: Changing the Display, Next: Regexp Matching, Prev: iswitchb-cust, Up: iswitchb + +5.2 Changing the Display +======================== + +If you have many matching buffers, they may not all fit onto one line +of the minibuffer. In this case, you should use +`(resize-minibuffer-mode)' *Note rsz-minibuf::. You can also limit +iswitchb so that it only shows a certain number of lines. To do this, +see the documentation for `iswitchb-minibuffer-setup-hook'. + + By default, the list of current buffers is most recent first, oldest +last, with the exception that the buffers visible in the current frame +are put at the end of the list. A hook exists to allow other functions +to order the list. For example, if you add: + + (add-hook 'iswitchb-make-buflist-hook 'iswitchb-summaries-to-end) + + then all buffers matching "Summary" are moved to the end of the +list. (I find this handy for keeping the INBOX Summary and so on out +of the way.) It also moves buffers matching "output\*$" to the end of +the list (these are created by AUC TeX when compiling.) Other +functions could be made available which alter the list of matching +buffers (either deleting or rearranging elements.) + + If you have font-lock loaded, the first matching buffer is +highlighted. To switch this off, set `(setq iswitchb-use-fonts nil)'. +I don't use font-lock that much, so I've hardcoded the faces. If this +is too harsh, let me know. Colouring of the matching buffer name was +suggested by Carsten Dominik (dominik@strw.leidenuniv.nl) + + +File: edit-utils.info, Node: Regexp Matching, Next: Replacement for read-buffer, Prev: Changing the Display, Up: iswitchb + +5.3 Regexp Matching +=================== + +There is limited provision for regexp matching within `iswitchb', +enabled through `iswitchb-regexp'. This allows you to type `c$' for +example and see all buffer names ending in `c'. This facility is quite +limited though in two respects. First, you can't currently type in +expressions like `[0-9]' directly - you have to type them in when +`iswitchb-regexp' is `nil' and then toggle on the regexp functionality. +Likewise, don't enter an expression containing `\' in regexp mode. If +you try, iswitchb gets confused, so just hit `C-g' and try again. +Secondly, no completion mechanism is currently offered when regexp +searching. + + +File: edit-utils.info, Node: Replacement for read-buffer, Prev: Regexp Matching, Up: iswitchb + +5.4 Replacement for read-buffer +=============================== + +iswitchb-read-buffer has been written to be a drop in replacement for +the normal buffer selection routine `read-buffer'. To use iswitch for +all buffer selections in Emacs, add: `(setq read-buffer-function +'iswitchb-read-buffer)' (This variable should be present in Emacs 20.3+) +XEmacs users can get the same behaviour by doing: `(defalias +'read-buffer 'iswitchb-read-buffer)' since `read-buffer' is defined in +lisp. + + +File: edit-utils.info, Node: permanent-buffers, Next: rsz-minibuf, Prev: iswitchb, Up: Top + +6 Permanent Buffers +******************* + +A permanent buffer is a buffer that you don't want to kill, mainly used +for testing or temporary stuff. The *scratch* buffer is the most famous +example of what could be a permanent buffer. This package allows you to +define several permanent buffers (the scratch buffer can be one of +them) that will never disappear. If you kill them or save their +contents, they will be regenerated. You can also specify a set of lisp +forms to eval in the buffer when it is (re)generated. + + This package is implemented in a minor-mode fashion. You can +customize the default value of `permanent-buffers-mode' or use +`turn-on-permanent-buffers' at startup. Within an XEmacs session, use +`permanent-buffers-mode' or `turn-o[n|ff]-permanent-buffers'. You might +also want to customize `permanent-buffers-alist'. + + To configure this package, type: + + M-x customize-group RET permanent-buffers RET + + +File: edit-utils.info, Node: rsz-minibuf, Next: search-buffers, Prev: permanent-buffers, Up: Top + +7 Self-Resizing Minibuffer +************************** + +This package allows the entire contents (or as much as possible) of the +minibuffer to be visible at once when typing. As the end of a line is +reached, the minibuffer will resize itself. When the user is done +typing, the minibuffer will return to its original size. + + In window systems where it is possible to have a frame in which the +minibuffer is the only window, the frame itself can be resized. + + Note that the minibuffer and echo area are not the same! They +simply happen to occupy roughly the same place on the frame. Messages +put in the echo area will not cause any resizing by this package. + + This package is considered a minor mode but it doesn't put anything +in minor-mode-alist because this mode is specific to the minibuffer, +which has no modeline. + + To invoke this mode, type: + + M-x resize-minibuffer-mode RET + + To configure this package, type: + + M-x customize-group RET resize-minibuffer RET + + +File: edit-utils.info, Node: search-buffers, Next: uniquify, Prev: rsz-minibuf, Up: Top + +8 Searching Many Buffers +************************ + +This package searches all live buffers for REGEXP and presents matching +lines in a separate buffer with hyperlinks to their occurrences. + + After creating countless buffers in an XEmacs session, the user can +execute the following: + + M-x list-matches-in-buffers RET \ RET .* RET + + to find all matches of the single word "problem" in any of them. +The result is presented in a buffer named "*Matches for "\" +in buffers*" with hyperlinks to any occurrence. User may navigate to +the next (`n') or previous (`p') match. + + +File: edit-utils.info, Node: uniquify, Next: winring, Prev: search-buffers, Up: Top + +9 Meaningful Unique Names +************************* + +Emacs' standard method for making buffer names unique adds <2>, <3>, +etc. to the end of (all but one of) the buffers. This file replaces +that behavior, for buffers visiting files and dired buffers, with a +uniquification that adds parts of the file name until the buffer names +are unique. For instance, buffers visiting `/u/mernst/tmp/Makefile' and +`/usr/projects/zaphod/Makefile' would be named `Makefile|tmp' and +`Makefile|zaphod', respectively (instead of `Makefile' and +`Makefile<2>'). Other buffer name styles are also available. + + To configure this package, type: + + M-x customize-group RET uniquify RET + + +File: edit-utils.info, Node: winring, Next: autorevert, Prev: uniquify, Up: Top + +10 Window Configuration Rings +***************************** + +This package provides lightweight support for circular rings of window +configurations. A window configuration is the layout of windows and +associated buffers within a frame. There is always at least one +configuration on the ring, the current configuration. You can create +new configurations and cycle through the layouts in either direction. +You can also delete configurations from the ring (except the last one +of course!). Window configurations are named, and you can jump to and +delete named configurations. + + Window configuration rings are frame specific. That is, each frame +has its own ring which can be cycled through independently of other +frames. + + You are always looking at the current window configuration for each +frame, which consists of the windows in the frame, the buffers in those +windows, and point in the current buffer. As you run commands such as +`C-x 4 b', `C-x 2', and `C-x 0' you are modifying the current window +configuration. When you jump to a new configuration, the layout that +existed before the jump is captured, and the ring is rotated to the +selected configuration. Window configurations are captured with +`current-window-configuration', however winring also saves point for the +current buffer. + + To use, add the following to your initialization file: + + (winring-initialize) + + Note that by default, this binds the winring keymap to the `C-x 7' +prefix, but you can change this by setting the value of +`winring-keymap-prefix', before you call `winring-initialize'. + + The following commands are defined: + +`C-x 7 n' + Create a new window configuration. The new configuration will + contain a single buffer, the one named in the variable + `winring-new-config-buffer-name'. + + With `C-u', winring prompts for the name of the new configuration. + If you don't use `C-u' the function in `winring-name-generator' + will be called to get the new configuration's name. + +`C-x 7 2' + Create a duplicate of the current window configuration. C-u has + the same semantics as with `C-x 7 c'. + +`C-x 7 j' + Jump to a named configuration (prompts for the name). + +`C-x 7 0' + Kill the current window configuration and rotate to the previous + layout on the ring. You cannot delete the last configuration in + the ring. With `C-u', prompts for the name of the configuration + to kill. + +`C-x 7 o' + Go to the next configuration on the ring. + +`C-x 7 p' + Go to the previous configuration on the ring. + + Note that the sequence `C-x 7 o C-x 7 p' is a no-op; it leaves you + in the same configuration you were in before the sequence. + +`C-x 7 r' + Rename the current window configuration. + +`C-x 7 b' + Submit a bug report on winring. + +`C-x 7 v' + Echo the winring version. + + + As mentioned, window configuration names can be displayed in the +modeline. The default value of `winring-show-names' is currently `nil' +by default. Set it to `t' to activate. If you don't like the position +in the modeline where winring names are shown, you can change this by +passing in your own modeline hacker function to `winring-initialize'. + +* Menu: + +* History:: +* Related Packages:: + + +File: edit-utils.info, Node: History, Next: Related Packages, Prev: winring, Up: winring + +10.1 History +============ + +A long long time ago there was a package called `wicos' written by +Heikki Suopanki, which was based on yet another earlier package called +`screens' also written by Suopanki. This in turn was based on the Unix +tty session manager `screen' (unrelated to Emacs) by Oliver Laumann, +Juergen Weigert, and Michael Schroeder. + + Wicos essentially provided fancy handling for window configurations. +I liked the basic ideas, but wicos broke with later versions of Emacs +and XEmacs. I re-implemented just the functionality I wanted, +simplifying things in the process, and porting the code to run with +XEmacs 19 and 20, and Emacs 20 (I don't know if winring works in Emacs +19.34). + + Wicos used the M-o prefix which I've recently changed to C-x 7 as the +default, by suggestion of RMS. Wicos also had some support for multiple +frames, and saving configurations on all visible frames, but it didn't +work too well, and I like frame independent rings better. + + +File: edit-utils.info, Node: Related Packages, Prev: History, Up: winring + +10.2 Related Packages +===================== + +I know of a few other related packages: + + * `escreen' by Noah Friedman. A much more ambitious package that + does Emacs window session management. Very cool, but I wanted + something more lightweight. + + * `wconfig' by Bob Weiner as part of Hyperbole. I think wconfig is + similar in spirit to winring; it seems to have also have named + window configurations, but not frame-specific window rings. + + * `winner' by Ivar Rummelhoff. This package comes with Emacs 20, + and appears to differ from winring by providing undo/redo + semantics to window configuration changes. winner is a minor mode + and does seem to support frame-specific window rings. + + * window-xemacs' by the XEmacs Development Team. It appears that + this package, which is specific to XEmacs (and perhaps just XEmacs + 20) implements stacks of window configurations which are frame + independent. + + + Please feel free to email me if my rendition of history, or my +explanation of the related packages, is inaccurate. + + +File: edit-utils.info, Node: autorevert, Next: backup-dir, Prev: winring, Up: Top + +11 Reverting Buffers +******************** + +Whenever a file that Emacs is editing has been changed by another +program the user normally has to execute the command `revert-buffer' to +load the new content of the file into Emacs. + + This package is defined in autorevert.el and contains two minor +modes: Global Auto-Revert Mode and Auto-Revert Mode. Both modes +automatically revert buffers whenever the corresponding files have been +changed on disk. + + Auto-Revert Mode can be activated for individual buffers. Global +Auto-Revert Mode applies to all file buffers. + + Both modes operate by checking the time stamp of all files at +intervals of `auto-revert-interval'. The default is every five +seconds. The check is aborted whenever the user actually uses Emacs. +You should never even notice that this package is active (except that +your buffers will be reverted, of course). + +* Menu: + +* Auto-Revert Usage:: How to use the package. + + +File: edit-utils.info, Node: Auto-Revert Usage, Prev: autorevert, Up: autorevert + +11.1 Auto-Revert Usage +====================== + +To configure the package, type: + + M-x customize-group RET auto-revert RET + + To activate Auto-Revert for a specific buffer, go to the buffer and +type: + + M-x auto-revert-mode RET + + To activate Global Auto-Revert Mode, type: + + M-x global-auto-revert-mode RET + + To activate Global Auto-Revert Mode every time Emacs is started +customize the option `global-auto-revert-mode' or the following line +could be added to your initialization file: + + (global-auto-revert-mode 1) + + The function `turn-on-auto-revert-mode' could be added to any major +mode hook to activate Auto-Revert Mode for all buffers in that mode. +For example, the following line will activate Auto-Revert Mode in all C +mode buffers: + + (add-hook 'c-mode-hook 'turn-on-auto-revert-mode) + + +File: edit-utils.info, Node: backup-dir, Next: bookmark, Prev: autorevert, Up: Top + +12 Specify Directories to be Used for Backup Files +************************************************** + +Allows backup files to be optionally stored in some directories, based +on the value of the alist, `bkup-backup-directory-info'. This variable +is a list of lists of the form `(FILE-REGEXP BACKUP-DIR OPTIONS ...)'. +If the filename to be backed up matches `FILE-REGEXP', or `FILE-REGEXP' +is `t', then `BACKUP-DIR' is used as the path for its backups. +Directories may begin with "/" to specify an absolute pathname. + + If `BACKUP-DIR' does not exist and `OPTIONS' contains the symbol +`ok-create', then it is created if possible. Otherwise the usual +behavior (backup in the same directory as the file) results. + + If `OPTIONS' contains the symbol `full-path', then the full path of +the file being backed up is prepended to the backup file name, with +each "/" replaced by a "!". This is intended for cases where an +absolute backup path is used. If `OPTIONS' contains `prepend-name' in +addition to `full-path', then the file name is prepended rather than +appended to the path component when forming the backup name. + + If `OPTIONS' contains the symbol `search-upward' and the backup +directory `BACKUP-DIR' is a relative path, then a directory with that +name is searched for starting at the current directory and proceeding +upward (.., ../.., etc) until one is found of that name or the root is +reached, and if one is found it is used as the backup directory. + + Finally, if no `FILE-REGEXP' matches the file name being backed up, +then the usual behavior results. + + These lines from my initialization file load this library and set +the values I like: + + (require 'backup-dir) + (setq bkup-backup-directory-info + '(("/home/greg/.*" "/~/.backups/" ok-create full-path prepend-name) + ("^/[^/:]+:" ".backups/") ; handle EFS files specially: don't + ("^/[^/:]+:" "./") ; search-upward... its very slow + (t ".backups/" + full-path prepend-name search-upward))) + + The package also provides a new function, `find-file-latest-backup' +to find the latest backup file for the current buffer's file. + + This package is based on `files.el' from XEmacs 20.3 and overrides +functions defined there. + + +File: edit-utils.info, Node: bookmark, Next: desktop, Prev: backup-dir, Up: Top + +13 Create annotated bookmarks +***************************** + +This package is for setting "bookmarks" in files. A bookmark +associates a string with a location in a certain file. Thus, you can +navigate your way to that location by providing the string. + + To configure this package, type: + + M-x customize-group RET bookmark RET + + +File: edit-utils.info, Node: desktop, Next: recent-files, Prev: bookmark, Up: Top + +14 Save Partial Status of Emacs When Killed +******************************************* + +Save the Desktop, i.e., + + * some global variables + + * the list of buffers with associated files. For each buffer also + + * the major mode + + * the default directory + + * the point + + * the mark & mark-active + + * buffer-read-only + + * some local variables + + + + To use this, first put these two lines at the bottom of your +initialization file (the later the better): + + (desktop-load-default) + (desktop-read) + + Between these two lines you may wish to add something that updates +the variables `desktop-globals-to-save' and/or +`desktop-locals-to-save'. If for instance you want to save the local +variable `foobar' for every buffer in which it is local, you could add +the line + + (setq desktop-locals-to-save (cons 'foobar desktop-locals-to-save)) + + To avoid saving excessive amounts of data you may also wish to add +something like the following + + (add-hook 'kill-emacs-hook + '(lambda () + (desktop-truncate search-ring 3) + (desktop-truncate regexp-search-ring 3))) + + which will make sure that no more than three search items are saved. +You must place this line _after_ the `(desktop-load-default)' line. +See also the variable `desktop-save-hook'. + + Start Emacs in the root directory of your "project". The desktop +saver is inactive by default. You activate it by typing `M-x +desktop-save RET'. When you exit the next time the above data will be +saved. This ensures that all the files you were editing will be +reloaded the next time you start Emacs from the same directory and that +points will be set where you left them. If you save a desktop file in +your home directory it will act as a default desktop when you start +Emacs from a directory that doesn't have its own. I never do this, but +you may want to. + + Some words on minor modes: Most minor modes are controlled by +buffer-local variables, which have a standard save / restore mechanism. +To handle all minor modes, we take the following approach: (1) check +whether the variable name from `minor-mode-alist' is also a function; +and (2) use translation table `desktop-minor-mode-table' in the case +where the two names are not the same. + + By the way: don't use `desktop.el' to customize Emacs - the standard +XEmacs initialization file is used for that. Saving global default +values for buffers is an example of misuse. + + PLEASE NOTE: The kill ring can be saved as specified by the variable +`desktop-globals-to-save' (by default it isn't). This may result in +saving things you did not mean to keep. Use `M-x desktop-clear RET'. + + To configure this package, type: + + M-x customize-group RET desktop RET + + +File: edit-utils.info, Node: recent-files, Next: resume, Prev: desktop, Up: Top + +15 Recent File Navigation +************************* + +To install `recent-files', put the following statements into your +initialization file + + (recent-files-initialize) + + `recent-files' adds the menu "Recent Files" (or whatever name you +choose, (*note Customization: recentf-cust.) to Emacs's menubar. Its +entries are the files (and directories) that have recently been opened +by Emacs. You can open one of these files again by selecting its entry +in the "Recent Files" menu. The list of file entries in this menu is +preserved from one Emacs session to another. You can prevent Emacs from +saving this list by selecting "Don't save recent-files list on exit" +from the menu. If you have disabled saving, you can re-enable it by +selecting "Save recent-files list on exit". + + The menu has permanent and non-permanent entries. Permanent entries +are marked with an asterisk in front of the filename. The non-permanent +entries are hidden in a submenu. + + Each time you open a file in Emacs, it is added as a non-permanent +entry to the menu. The value of `recent-files-number-of-entries' +determines how many non-permanent entries are held in the menu. When +the number of non-permanent entries reaches this value, the least +recently added non-permanent entry is removed from the menu when +another non-permanent entry is added. It is not removed from the list, +though; it may reappear when entries are deleted from the list. The +number of entries saved to disk is the value of the variable +`recent-files-number-of-saved-entries'. + + Permanent entries are not removed from the menu. You can make a file +entry permanent by selecting "Make permanent" (where +is the name of the current buffer) when the current buffer holds this +file. "Make non-permanent" makes the file entry of the current +buffer non-permanent. + + The command "Kill buffer and delete entry" is handy when +you have accidentally opened a file but want to keep neither the buffer +nor the entry. + + You can erase the list of non-permanent entries by selecting "Erase +non-permanent entries" from the menu. + +* Menu: + +* Customization: recentf-cust. + + +File: edit-utils.info, Node: recentf-cust, Prev: recent-files, Up: recent-files + +15.1 Customization +================== + +There are lots of variables to control the behaviour of recent-files. +You do not have to change any of them if you like it as it comes out of +the box. However, you may want to look at these options to make it +behave different. + +`recent-files-number-of-entries' + Controls how many non-permanent entries are shown in the + recent-files list. The default is 15. + +`recent-files-number-of-saved-entries' + Controls how many non-permanent entries are saved to disk when + Emacs exits or recent-files-save-the-list is called. The default + is 50. + +`recent-files-save-file' + The name of the file where the recent-files list is saved between + Emacs session. You probably don't need to change this. The + default is ".recent-files.el" in your home directory. + +`recent-files-dont-include' + A list of regular expressions for files that should not be + included into the recent-files list. This list is empty by + default. For instance, a list to exclude all .newsrc files, all + auto-save-files, and all files in the /tmp directory (but not the + /tmp directory itself) would look like this: + + (setq recent-files-dont-include + '("/\\.newsrc" "~$" "^/tmp/.")) + + The default is empty. + +`recent-files-use-full-names' + If the value of this variable is non-nil, the full pathnames of + the files are shown in the recent-files menu. Otherwise only the + filename part (or the last name component if it is a directory) is + shown in the menu. The default it t, i.e. show full names. + +`recent-files-filename-replacements' + This is a list of pairs of regular expressions and replacement + strings. If a filename matches one of the regular expressions, the + matching part is replaced by the replacement string for display in + the recent-files menu. Example: My home directory is + "/users/mmc/nickel/". I want to replace it with "~/". I also want + to replace the directory "/imports/teleservices/mmc/avc2/", where + I work a lot, with ".../avc2/". The list then looks like + + (setq recent-files-filename-replacements + '(("/users/mmc/nickel/" . "~/") + ("/imports/teleservices/mmc/avc2/" . ".../avc2/"))) + + Only the first match is replaced. So, if you have several entries + in this list that may match a filename simultaneously, put the one + you want to match (usually the most special) in front of the + others. The default is to replace the home directory with "~". + +`recent-files-sort-function' + Contains a function symbol to sort the display of filenames in the + recent-files menu. Supplied are two functions, + `recent-files-dont-sort' and `recent-files-sort-alphabetically'. + The first, which is the default, preserves the order of "most + recent on top". + +`recent-files-permanent-submenu' + If this variable is non-nil, the permanent entries are put into a + separate submenu of the recent-files menu. The default is nil. + +`recent-files-non-permanent-submenu' + If this variable is non-nil, the non-permanent entries are put + into a separate submenu of the recent-files menu. The default is + currently t, but probably should be nil, and we may change it + back. (You can set both `recent-files-permanent-submenu' and + `recent-files-non-permanent-submenu' to t to have both lists in + separate submenus.) + +`recent-files-commands-submenu' + If this variable is non-nil, the commands if recent-files are + placed in a submenu of the recent-files menu. The default is nil. + +`recent-files-commands-submenu-title' + If the commands are placed in a submenu, this string is used as + the title of the submenu. The default is "Commands...". + +`recent-files-actions-on-top' + If this variable is non-nil, the "action" menu entries ("Make + permanent" etc.) are put on top of the menu. Otherwise + they appear below the file entries or submenus. The default is nil. + +`recent-files-permanent-first' + If this variable is t, the permanent entries are put first in the + recent-files menu, i.e. above the non-permanent entries. If the + value is nil, non-permanent entries appear first. If the value is + neither t nor nil, the entries are sorted according to + recent-files-sort-function. The default is 'sort. + +`recent-files-find-file-command' + This variable contains the command to execute when a file entry is + selected from the menu. Usually this will be `find-file', which is + the default. + + + +File: edit-utils.info, Node: resume, Next: saveconf, Prev: recent-files, Up: Top + +16 Resuming a Suspended Emacs Job +********************************* + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: saveconf, Next: savehist, Prev: resume, Up: Top + +17 Save Buffer/Window Configuration Between Sessions +**************************************************** + +This package of functions gives Emacs the ability to remember which +files were being visited, the windows that were on them, and the value +of point in their buffers the last Emacs session in the same directory. +This is an emulation of an old Gosling Emacs feature. + + The relevant commands are `save-context' and `recover-context'. + + Most of the time you'll want an Emacs session's context saved even +if you choose not to recover it later. To avoid having to manually `M-x +save-context' at each emacs exit, put the line: + + (setq auto-save-and-recover-context t) + + in your initialization file or in `default.el' in the lisp directory +of the Emacs distribution. The context will then automatically be +saved when Emacs exits. + + By default only the contexts of visible buffers (buffers with +windows on them) are saved. Setting the variable save-buffer-context +to t causes the contexts of all buffers to be saved. + + To use the package put these lines + + (require 'saveconf) + (if (null (cdr command-line-args)) + (setq inihibit-startup-message (recover-context))) + + at the end of your initialization file or the `default.el' file in +the lisp directory of the Emacs distribution. This causes the context +saved in the current directory to be recovered whenever Emacs is +invoked without any arguments. + + +File: edit-utils.info, Node: savehist, Next: saveplace, Prev: saveconf, Up: Top + +18 Save Minibuffer History +************************** + +Many editors (e.g. Vim) have the feature of saving minibuffer history +to an external file after exit. This package provides the same feature +in Emacs. When Emacs is about the exit, `savehist-save' will dump the +contents of various minibuffer histories (as determined by +`savehist-history-variables') to a save file (`~/.emacs-history' by +default). Although the package was designed for saving the minibuffer +histories, any variables can be saved that way. + + To use savehist, put the following in your initialization file: + + (savehist-load) + + To configure this package, type: + + M-x customize-group RET savehist RET + + +File: edit-utils.info, Node: saveplace, Next: where-was-i-db, Prev: savehist, Up: Top + +19 Automatically Save Place in Files +************************************ + +Automatically save place in files, so that visiting them later (even +during a different Emacs session) automatically moves point to the +saved position, when the file is first found. Uses the value of +buffer-local variable `save-place' to determine whether to save +position or not. + + To use this package, put the following in your initialization file: + + (require 'saveplace) + + To configure this package, type: + + M-x customize-group RET saveplace RET + + +File: edit-utils.info, Node: where-was-i-db, Next: completion, Prev: saveplace, Up: Top + +20 Keep Persistent State in Visited Files +***************************************** + +This library will make XEmacs keep track of where you were last time you +visited a file. It hopes to become a standard and favored XEmacs +feature on setups with Berkeley DB installed. + + It works by installing functions on the `find-file-hooks' and on the +buffer-local `kill-buffer-hook'. When a buffer is killed, if it was +visiting a file, and place saving has been enabled for it, a database +entry is made, saving the location of `point'. When you visit a file, +the database is queried, keyed on `buffer-file-name', and if an entry is +found, point is set to the value retrieved, and place saving is enabled +again for that buffer. + + There is a command, which is initially not bound to a keystroke in +this incarnation; and may never be, since I think completion works well +enough: + + M-x toggle-where-was-i + + which, using auto-completion, can be entered as + + M-x tog TAB w TAB + + that will turn place saving on and off on a per-file, buffer- local +basis. If `where-was-i-db' has been turned off in a buffer and then +you kill it, or exit XEmacs, any record for that file will be purged +from the database, and you'll start at the top of the file next time +you open it, with place saving turned off there. + + Place saving is automatically still `on' when you visit a file you'd +toggled it on for in a previous session or visitation. (That's the +point of it, after all.) + + Toggling place saving on in a buffer visiting a file is all that is +required to cause the `where-was-i-db' feature to be autoloaded, as +`toggle-where-was-i' will call on `install-where-was-i' if the +`wwi-ffh' has not yet been installed. That WILL NOT cause this feature +to be automatically enabled in your next XEmacs invocation, however. +For that, you must customize and save +`wwi-auto-install-on-startup-flag'. There is more information about +this in its docstring. + + This feature can be unloaded with: + + C-u M-x install-where-was-i + + which will call `unload-feature', as well as traverse the +`buffer-list' removing the buffer-local `kill-buffer-hook' installed by +this program. Note that any buffers that got place saving enabled by +having had an entry in the database for them when they were first +visited (thus restoring point to where it was the last time you had +visited the file), will not have an updated entry made, nor the old +entry removed (as would happen if you `toggle-where-was-i' to off in +just that buffer), after you uninstall this feature like that. + + If you toggle it on again in a buffer visiting a file, then kill +that buffer, the point will be saved for it. When you kill the other +buffers that had place saving enabled before you uninstalled the +feature with `C-u M-x install-where-was-i', no `where-was-i-db' +database update will happen for them, since their buffer-local +`kill-buffer-hook' will have been cleaned of the member +`wwi-save-where-i-am', the function that writes the `point' entry to +the database when a buffer is killed. If you then re-visit one of +those files, point will get restored to the location it did the last +time you visited that file with `where-was-i-db' installed. + + To remove a file from the place saving database, simply visit it, +`M-x toggle-where-was-i' to switch `where-was-i-db' off, then kill that +buffer. You can see how this works by looking at the definition of +`wwi-save-where-i-am'. + + After a period of time, the database of saved file positions will +become cluttered with the names of files that no longer exist. You may +vacume out the crumbs using: + + M-x wwi-vacume-where-was-i-db + + which will prompt you for an optional regular expression to match +files you want records removed for. It will traverse the database and +remove entries for file names that either match the regexp, or that are +`(not (file-exists-p file-name))'. The main reason for this command is +the removal of stale entries, for files that no longer exist on the +filesystem. + + Note also that running `wwi-vacume-where-was-i-db' will cause EFS +traffic, if you've saved your place in any remote files. Don't be +surprised if your dialing daemon picks up the phone when you run the +vacume function. You should be able to purge the database of all EFS +entries with a simple regular expression passed to +`wwi-vacume-where-was-i-db'. Of course, you might not want to do that, +for obvious reasons. + + To configure this package, type: + + M-x customize-group RET where-was-i RET + + +File: edit-utils.info, Node: completion, Next: dabbrev, Prev: where-was-i-db, Up: Top + +21 Completion +************* + +To load this package, add the following to your initialization file: + + (require 'completion) + + After you type a few characters, pressing the "complete" key inserts +the rest of the word you are likely to type. + + This watches all the words that you type and remembers them. When +typing a new word, pressing "complete" (`C-return') "completes" the +word by inserting the most recently used word that begins with the same +characters. If you press meta-return repeatedly, it cycles through all +the words it knows about. + + If you like the completion then just continue typing, it is as if +you entered the text by hand. If you want the inserted extra +characters to go away, type `C-w' or delete. More options are +described below. + + The guesses are made in the order of the most recently "used". +Typing in a word and then typing a separator character (such as a +space) "uses" the word. So does moving a cursor over the word. If no +words are found, it uses an extended version of dynamic abbreviation +*Note dabbrev::. + + Completions are automatically saved to a file between sessions. + + Completion enables programmers to enter longer, more descriptive +variable names while typing fewer keystrokes than they normally would. + + To configure this package, type: + + M-x customize-group RET completion RET + + +File: edit-utils.info, Node: dabbrev, Next: hippie-exp, Prev: completion, Up: Top + +22 Dynamic Abbreviations +************************ + +The purpose with this package is to let you write just a few characters +of words you've written earlier to be able to expand them. + + To expand a word, just put the point right after the word and press +`M-/' (`dabbrev-expand') or `M-C-/' (`dabbrev-completion'). + + Check out the customizable variables to learn about all the features +of this package. + + To configure this package, type: + + M-x customize-group RET dabbrev RET + + +File: edit-utils.info, Node: hippie-exp, Next: icomplete, Prev: dabbrev, Up: Top + +23 Hippie Expand +**************** + +`hippie-expand' is a single function for a lot of different kinds of +completions and expansions. Called repeatedly it tries all possible +completions in succession. Which kinds of completions to try, and in +which order, is determined by the contents of +`hippie-expand-try-functions-list'. Much customization of +`hippie-expand' can be made by changing the order of, removing, or +inserting new functions in this list. Given a positive numeric +argument, `hippie-expand' jumps directly ARG functions forward in this +list. Given some other argument (a negative argument or just `C-u') it +undoes the tried completion. + + If the variable `hippie-expand-verbose' is non-nil, `hippie-expand' +outputs in a message which try-function in the list that is used +currently (ie. was used currently and will be tried first the next +time). + + The variable `hippie-expand-max-buffers' determines in how many +buffers, apart from the current, to search for expansions in. It is +used by the try-functions named "-all-buffers". The variable +`hippie-expand-ignore-buffers' is a list of regexps matching buffer +names (as strings) or major modes (as atoms) of buffers that should not +be searched by the try-functions named "-all-buffers". See also the +macro `make-hippie-expand-function' below. + + A short description of the current try-functions in this file: + +`try-complete-file-name' + Very convenient to have in any buffer, and not just in the + minibuffer or (some) shell-mode. It goes through all possible + completions instead of just completing as much as is unique. + +`try-complete-file-name-partially' + To insert in the list just before `try-complete-file-name' for + those who want first to get a file name completed only as many + characters as is unique. + +`try-expand-all-abbrevs' + Can be removed if you don't use abbrevs. Otherwise it looks + through all abbrev-tables, starting with the local followed by the + global. + +`try-expand-line' + Searches the buffer for an entire line that begins exactly as the + current line. Convenient sometimes, for example as a substitute + for (or complement to) the history list in shell-like buffers. At + other times, only confusing. + +`try-expand-line-all-buffers' + Like `try-expand-line' but searches in all buffers (except the + current). (This may be a little slow, don't use it unless you are + really fond of `hippie-expand'.) + +``try-expand-list' + Tries to expand the text back to the nearest open delimiter, to a + whole list from the buffer. Convenient for example when writing + lisp or TeX. + +`try-expand-list-all-buffers' + Like `try-expand-list' but searches in all buffers (except the + current). + +`try-expand-dabbrev' + Works exactly as `dabbrev-expand' (but of course in a way + compatible with the other try-functions). + +`try-expand-dabbrev-all-buffers' + Perhaps the most useful of them, like `dabbrev-expand' but + searches all Emacs buffers (except the current) for matching + words. (No, I don't find this one particularly slow.) + +`try-expand-dabbrev-visible' + Searches the currently visible parts of all windows. Can be put + before `try-expand-dabbrev-all-buffers' to first try the + expansions you can see. + +`try-expand-dabbrev-from-kill' + Searches the kill ring for a suitable completion of the word. + Good to have, just in case the word was not found elsewhere. + +`try-expand-whole-kill' + Tries to complete text with a whole entry from the kill ring. May + be good if you don't know how far up in the kill-ring the required + entry is, and don't want to mess with "Choose Next Paste". + +`try-complete-lisp-symbol' + Like `lisp-complete-symbol', but goes through all possibilities + instead of completing what is unique. Might be tedious (usually a + lot of possible completions) and since its function is much like + `lisp-complete-symbol', which already has a key of its own, you + might want to remove this. + +`try-complete-lisp-symbol-partially' + To insert in the list just before `try-complete-lisp-symbol' for + those who first want to get completion of what is unique in the + name. + + + Not all of the above functions are by default in +`hippie-expand-try-functions-list'. This variable is better set in your +initialization file to make `hippie-expand' behave maximally convenient +according to personal taste. Also, instead of loading the variable +with all kinds of try-functions above, it might be an idea to use +`make-hippie-expand-function' to construct different +`hippie-expand'-like functions, with different try-lists and bound to +different keys. It is also possible to make +`hippie-expand-try-functions-list' a buffer local variable, and let it +depend on the mode (by setting it in the mode-hooks). + + +File: edit-utils.info, Node: icomplete, Next: tempo, Prev: hippie-exp, Up: Top + +24 Interactive Minibuffer Completion +************************************ + +Loading this package implements a more fine-grained minibuffer +completion feedback scheme. Prospective completions are concisely +indicated within the minibuffer itself, with each successive keystroke. + + See `icomplete-completions' docstring for a description of the +icomplete display format. + + See the `icomplete-minibuffer-setup-hook' docstring for a means to +customize icomplete setup for interoperation with other +minibuffer-oriented packages. + + To activate `icomplete mode', load the package and use the +`icomplete-mode' function. You can subsequently deactivate it by +invoking the function `icomplete-mode' with a negative prefix-arg `(C-U +-1 ESC-x icomplete-mode'). Also, you can prevent activation of the +mode during package load by first setting the variable `icomplete-mode' +to nil. Icompletion can be enabled any time after the package is +loaded by invoking `icomplete-mode' without a prefix arg. + + To configure this package, type: + + M-x customize-group RET icomplete RET + + +File: edit-utils.info, Node: tempo, Next: avoid, Prev: icomplete, Up: Top + +25 Flexible Template Insertion +****************************** + +This file provides a simple way to define powerful templates, or +macros, if you wish. It is mainly intended for, but not limited to, +other programmers to be used for creating shortcuts for editing certain +kind of documents. It was originally written to be used by a HTML +editing mode written by Nelson Minar , and his +`html-helper-mode.el' is probably the best example of how to use this +program. + + A template is defined as a list of items to be inserted in the +current buffer at point. Some of the items can be simple strings, while +other can control formatting or define special points of interest in +the inserted text. + + If a template defines a "point of interest" that point is inserted +in a buffer-local list of "points of interest" that the user can jump +between with the commands `tempo-backward-mark' and +`tempo-forward-mark'. If the template definer provides a prompt for the +point, and the variable `tempo-interactive' is non-nil, the user will +be prompted for a string to be inserted in the buffer, using the +minibuffer. + + The template can also define one point to be replaced with the +current region if the template command is called with a prefix (or a +non-nil argument). + + More flexible templates can be created by including lisp symbols, +which will be evaluated as variables, or lists, which will be evaluated +as lisp expressions. + + See the documentation for `tempo-define-template' for the different +items that can be used to define a tempo template. + + One of the more powerful features of tempo templates are automatic +completion. With every template can be assigned a special tag that +should be recognized by `tempo-complete-tag' and expanded to the +complete template. By default the tags are added to a global list of +template tags, and are matched against the last word before point. But +if you assign your tags to a specific list, you can also specify +another method for matching text in the buffer against the tags. In the +HTML mode, for instance, the tags are matched against the text between +the last `<' and point. + + When defining a template named `foo', a symbol named +`tempo-template-foo' will be created whose value as a variable will be +the template definition, and its function value will be an interactive +function that inserts the template at the point. + + To configure this package, type: + + M-x customize-group RET tempo RET + + +File: edit-utils.info, Node: avoid, Next: blink-cursor, Prev: tempo, Up: Top + +26 Move Mouse Pointer Out of the Way of Editing +*********************************************** + +For those who are annoyed by the mouse pointer obscuring text, this mode +moves the mouse pointer - either just a little out of the way, or all +the way to the corner of the frame. To use, type `M-x +mouse-avoidance-mode'. To set up permanently, add the following to +your initialization file: + + (if window-system (mouse-avoidance-mode 'animate)) + + The `'animate' can be `'jump' or `'banish' or `'exile' or `'protean' +if you prefer. See the documentation for function +`mouse-avoidance-mode' for details of the different modes. + + For added silliness, make the animatee animate by put something +similar to the following into your initialization file: + + (if window-system + (mouse-avoidance-set-pointer-shape + (eval (nth (random 4) + '(x-pointer-man x-pointer-spider + x-pointer-gobbler x-pointer-gumby))))) + + For completely random pointer shape, replace the `setq' above with +`(setq x-pointer-shape (mouse-avoidance-random-shape))'. + + To configure this package, type: + + M-x customize-group RET avoid RET + + +File: edit-utils.info, Node: blink-cursor, Next: fast-lock, Prev: avoid, Up: Top + +27 Blinking Cursor +****************** + +To activate this package, type: + + M-x blink-cursor-mode RET + + To configure this package, type: + + M-x customize-group RET blink-cursor RET + + +File: edit-utils.info, Node: fast-lock, Next: lazy-lock, Prev: blink-cursor, Up: Top + +28 Speeding Up Font Lock Mode +***************************** + +Lazy Lock mode is a Font Lock support mode. It makes visiting a file +in Font Lock mode faster by restoring its face text properties from +automatically saved associated Font Lock cache files. + + See also the lazy-lock package. (But don't use the two at the same +time!) + + To use this package, add the following to your initialization file: + + (setq font-lock-support-mode 'fast-lock-mode) + + Start up a new Emacs and use font-lock as usual (except that you can +use the so-called "gaudier" fontification regexps on big files without +frustration). + + When you visit a file (which has `font-lock-mode' enabled) that has a +corresponding Font Lock cache file associated with it, the Font Lock +cache will be loaded from that file instead of being generated by Font +Lock code. + + To configure this package, type: + + M-x customize-group RET fast-lock RET + + +File: edit-utils.info, Node: lazy-lock, Next: lazy-shot, Prev: fast-lock, Up: Top + +29 Lazy Demand-Driven Fontification +*********************************** + +The purpose of this library is to make visiting buffers in +`font-lock-mode' faster by making fontification demand-driven and +stealthy. Fontification only occurs when, and where, necessary. + + See also the fast-lock and lazy-shot packages. (But don't use them +at the same time as lazy-lock!) + + To use this package, add the following to your initialization file: + + (setq font-lock-support-mode 'lazy-lock-mode) + + Start up a new XEmacs and use font-lock as usual (except that you +can use the so-called "gaudier" fontification regexps on big files +without frustration). + + In a buffer (which has `font-lock-mode' enabled) which is at least +`lazy-lock-minimum-size' characters long, only the visible portion of +the buffer will be fontified. Motion around the buffer will fontify +those visible portions that were not previous fontified. + + If stealth fontification is enabled, fontification will occur in +invisible parts of the buffer after `lazy-lock-stealth-time' seconds of +idle time. + + To configure this package, type: + + M-x customize-group RET lazy-lock RET + + +File: edit-utils.info, Node: lazy-shot, Next: mic-paren, Prev: lazy-lock, Up: Top + +30 Another Lazy Demand-Driven Fontification +******************************************* + +This is an experimental demand based font-lock implementation. It is +experimental in the sense that it relies on C support from the redisplay +engine, that is experimental. The code in this file is more or less +finished. The C code support experimental because the current design is +rumoured to be ugly. Secondly because XEmacs does actually display the +"un-font-locked" parts of the buffer first, the user notices flashing +as the buffer is repainted with color/fonts. + + To use this package, add the following to your initialization file: + + (add-hook 'font-lock-mode-hook 'turn-on-lazy-shot) + + Do not use in combination with `lazy-lock'. + + M-x customize-group RET lazy-shot RET + + +File: edit-utils.info, Node: mic-paren, Next: paren, Prev: lazy-shot, Up: Top + +31 Advanced Highlighting of Matching Parentheses +************************************************ + +Load this file, activate it and Emacs will display highlighting on +whatever parenthesis (and paired delimiter if you like this) matches +the one before or after point. This is an extension to the paren.el +file distributed with Emacs. The default behaviour is similar to +paren.el but more sophisticated. Normally you can try all default +settings to enjoy mic-paren. + + Or - if you are a LaTeX writer like the current maintainer - try the +following additional setup in your initialization file: + + ;; In LaTeX-mode we want this + (add-hook 'LaTeX-mode-hook + (function (lambda () + (paren-toggle-matching-quoted-paren 1) + (paren-toggle-matching-paired-delimiter 1)))) + + Or - if you are programming in C like languages - try also: + + (add-hook 'c-mode-common-hook + (function (lambda () + (paren-toggle-open-paren-context 1)))) + + `mic-paren.el' is an extension and replacement to the packages +`paren.el' and `stig-paren.el' for Emacs. When mic-paren is active +Emacs normal parenthesis matching is deactivated. Instead parenthesis +matching will be performed as soon as the cursor is positioned at a +parenthesis. The matching parenthesis (or the entire expression between +the parentheses) is highlighted until the cursor is moved away from the +parenthesis. + + Features include: + + * Both forward and backward parenthesis matching (simultaneously if + cursor is between two expressions). + + * Indication of mismatched parentheses. + + * Recognition of "escaped" (also often called "quoted") parentheses. + + * Option to match "escaped" parens too, especially in (La)TeX-mode + (e.g. matches expressions like "\(foo bar\)" properly). + + * Offers two functions as replacement for `forward-sexp' and + `backward-sexp' which handle properly quoted parens (s.a.). These + new functions can automatically be bounded to the original binding + of the standard `forward-sexp' and `backward-sexp' functions. + + * Option to activate matching of paired delimiter (i.e. characters + with syntax '$'). This is useful for writing in LaTeX-mode for + example. + + * Option to select in which situations (always, never, if match, if + mismatch) the entire expression should be highlighted or only the + matching parenthesis. + + * Message describing the match when the matching parenthesis is + off-screen (vertical and/or horizontal). Message contains either + the linenumber or the number of lines between the two matching + parens. Option to select in which cases this message should be + displayed. + + * Optional delayed highlighting (useful on slow systems), + + * Functions to activate/deactivate `mic-paren.el' are provided. + + * Numerous options to control the behaviour and appearance of + `mic-paren.el'. + + + To configure this package, type: + + M-x customize-group RET mic-paren-matching RET + + +File: edit-utils.info, Node: paren, Next: shell-font, Prev: mic-paren, Up: Top + +32 Highlight (Un)matching Parens and Whole Expressions +****************************************************** + +This package highlights matching parens (or whole sexps) for easier +editing of source code, particularly lisp source code. + + The `paren-highlight' hook function runs after each command and +checks to see if the cursor is at a parenthesis. If so, then it +highlights, in one of several ways, the matching parenthesis. + + Priority is given to matching parentheses right before the cursor +because that's what makes sense when you're typing a lot of closed +parentheses. This is especially intuitive if you frequently use +`forward-sexp' (`M-C-f') and `backward-sexp' (`M-C-b') to maneuver +around in source code. + + Different faces are used for matching and mismatching parens so that +it is easier to see mistakes as you type them. Audible feedback is +optional. + + If a (mis)matching paren is offscreen, then a message is sent to the +modeline. + + If `paren-mode' is `sexp', entire S-expressions are highlighted +instead of just matching parens. + + To configure this package, type: + + M-x customize-group RET paren-matching RET + + +File: edit-utils.info, Node: shell-font, Next: highline, Prev: paren, Up: Top + +33 Decorate a Shell Buffer With Fonts +************************************* + +Do this: `(add-hook 'shell-mode-hook 'install-shell-fonts)' and the +prompt in your shell-buffers will appear bold-italic, process output +will appear in normal face, and typein will appear in bold. + + The faces `shell-prompt', `shell-input' and `shell-output' can be +modified as desired, for example, `(copy-face 'italic 'shell-prompt)'. + + +File: edit-utils.info, Node: highline, Next: after-save-commands, Prev: shell-font, Up: Top + +34 Highlight the Current Line in the Buffer +******************************************* + +This package is a minor mode to highlight the current line in buffer. + + The mode supports the following modes of operation: + + * LOCAL highline + + * GLOBAL highline + + * INDIRECT highline + + + Both Local and Global minor modes may be in use at the same time. + + Indirect highline (`highline-view-on', `highline-view-off' and +`highline-view-mode') is useful when you wish to have various "visions" +of the same buffer. Indirect highline uses an indirect buffer to get +the "vision" of the buffer. So, if you kill an indirect buffer, the +base buffer is not affected; if you kill the base buffer, all indirect +buffer related with the base buffer is automagically killed. Also, any +text insertion/deletion in any indirect or base buffer is updated in +all related buffers. + +* Menu: + +* Key Bindings and Example Usage: highline-keys. +* Hooks: highline-hooks. +* Options: highline-options. + + +File: edit-utils.info, Node: highline-keys, Next: highline-hooks, Prev: highline, Up: highline + +34.1 Key Bindings and Example Usage +=================================== + +It might be useful to set up some global key bindings as follows: + + (global-set-key "\C-c\C-a" 'highline-on) + (global-set-key "\C-c\C-b" 'highline-off) + (global-set-key "\C-c\C-l" 'highline-local-mode) + (global-set-key "\C-c\C-d" 'highline-mode-on) + (global-set-key "\C-c\C-e" 'highline-mode-off) + (global-set-key "\C-c\C-g" 'highline-mode) + (global-set-key "\C-c\C-c" 'highline-customize) + (global-set-key "\C-c\C-v\C-n" 'highline-view-on) + (global-set-key "\C-c\C-v\C-f" 'highline-view-off) + (global-set-key "\C-c\C-v\C-t" 'highline-view-mode) + + As an example, try to insert this in your .emacs file: + + (require 'highline) + ;; Turn on local highlighting for Dired (C-x d) + (add-hook 'dired-after-readin-hook 'highline-on) + ;; Turn on local highlighting for list-buffers (C-x C-b) + (defadvice list-buffers (after highlight-line activate) + (save-excursion + (set-buffer "*Buffer List*") + (highline-on))) + + +File: edit-utils.info, Node: highline-hooks, Next: highline-options, Prev: highline-keys, Up: highline + +34.2 Hooks +========== + +highline has the following hook variables: + +`highline-hook' + It is evaluated always when highline is turned on globally. + +`highline-local-hook' + It is evaluated always when highline is turned on locally. + +`highline-view-hook' + It is evaluated always when indirect highline is turned on. + +`highline-load-hook' + It is evaluated after highline package is loaded. + + + +File: edit-utils.info, Node: highline-options, Prev: highline-hooks, Up: highline + +34.3 Options +============ + +This is a brief description of highline options. Please see the options +declarations in the code for more detail. + +`highline-face' + Specify face used to highlight the current line. + +`highline-vertical-face' + Specify face used to highlight other than current line. + +`highline-line' + Specify which part of line should be highlighted. + +`highline-vertical' + Specify how many vertical lines should be highlighted. + +`highline-verbose' + Non-nil means generate messages. + +`highline-ignore-regexp' + Specify regexp for buffers to ignore. + +`highline-priority' + Specify highline overlay priority. + +`highline-selected-window' + Non-nil means highlight current line on current window. + + + To configure this package, type: + + M-x highline-customize RET + + +File: edit-utils.info, Node: after-save-commands, Next: atomic-extents, Prev: highline, Up: Top + +35 Hooks Invoked After Saving a File +************************************ + +Set up a list of file-name matching regular expressions associated with +shell commands or lisp forms to run after saving the file. + + This is good for things like running `newaliases(1)' on +`/etc/aliases', `xrdb(1)' on `~/.Xresources', installing a new +`~/.crontab', as well as for sending signals to daemons whose +configuration files you've just finished editing. + + It is much safer and more powerful than using exec statements in +"Local Variables" sections, and can safely be used by root for system +administration tasks. The shell command can run about anything you can +think of. + + See variable `After-save-alist' for more information. + + +File: edit-utils.info, Node: atomic-extents, Next: array, Prev: after-save-commands, Up: Top + +36 Indivisible Blocks of Text +***************************** + +Point is not allowed to fall inside of an atomic extent. This has the +effect of making all text covered by an atomic extent be treated as a +single object. Normally point will be adjusted to an end of an atomic +extent in the direction of motion. If point appears inside of an +atomic extent (via `goto-char' for example), point will be adjusted to +the side closest to the entry point. + + To make this feature available, add the following to your +initialization file: + + (require 'atomic-extents) + + To make an extent atomic use the command: + + (set-extent-property # 'atomic t) + + +File: edit-utils.info, Node: array, Next: floating-toolbar, Prev: atomic-extents, Up: Top + +37 Table and Array Editor +************************* + +Commands for editing a buffer interpreted as a rectangular array or +matrix of whitespace-separated strings. You specify the array +dimensions and some other parameters at startup time. + + +File: edit-utils.info, Node: floating-toolbar, Next: The Toolbar Utilities, Prev: array, Up: Top + +38 Floating Toolbar +******************* + +The command `floating-toolbar' pops up a small frame containing a +toolbar. The command should be bound to a button-press event. If the +mouse press happens over an extent that has a non-nil +`'floating-toolbar' property, the value of that property is the toolbar +instantiator that will be displayed. Otherwise the toolbar displayed +is taken from the variable `floating-toolbar'. This variable can be +made buffer local to produce buffer local floating toolbars. + + `floating-toolbar-or-popup-mode-menu' works like `floating-toolbar' +except that if no toolbar is found, `popup-mode-menu' is called. + + `floating-toolbar-from-extent-or-popup-mode-menu' works like +`floating-toolbar-or-popup-mode-menu' except only extent local toolbars +are used; the value of floating-toolbar is not used. + + Add the following line to your initialization file: + + (require 'floating-toolbar) + + You will also need to bind a mouse click to `floating-toolbar' or to +`floating-toolbar-or-popup-mode-menu'. + + +File: edit-utils.info, Node: The Toolbar Utilities, Next: foldout, Prev: floating-toolbar, Up: Top + +39 The Toolbar Utilities +************************ + +The toolbar utilities are a set of Emacs commands and Lisp functions for +convenient creation and management of toolbars. Common usages such as +creating and adding toolbar buttons to invoke commands and keyboard +macros are implemented as user commands. Convenience APIs are provided +to create buttons, add them to toolbars, kill them from toolbars, and +finding a particular button, or a button with certain content, in a +toolbar. + + The toolbar utilities are implemented in three files: + +`toolbar-utils.el' + The toolbar utility APIs and user commands. + +`edit-toolbar.el' + The near-WYSIWYG toolbar editor by Peter D. Pezaris. + +`xemacs-toolbar.el' + The XEmacs compatibility API for programs that should also run + under GNU Emacs. + + The author would like to thank Jeff Miller and Peter D. Pezaris for +the original API and the toolbar editor, respectively, and David +Kastrup and Jamie Zawinski for the pedal-gluteal impetus that resulted +in the recent revision of these libraries described in this manual. + +* Menu: + +* Adding Buttons on the Fly:: Quick and convenient. +* The Toolbar Editor:: Power tools for customization. +* APIs for Adding and Killing:: For Lisp programmers. +* APIs for Search:: Button, button, who's got the button? +* Toolbar Portability:: The `xemacs-toolbar.el' library. + + +File: edit-utils.info, Node: Adding Buttons on the Fly, Next: The Toolbar Editor, Prev: The Toolbar Utilities, Up: The Toolbar Utilities + +39.1 Adding Buttons on the Fly +============================== + + -- Group: edit-toolbar + Customize group of tools for interactive editing and + non-interactive management of toolbars. + + -- Variable: toolbar-button-default-position + Default position for adding toolbar buttons on the fly. The value + may be a non-negative integer (0 is leftmost), or one of the + symbols `left', `right', or `extreme-right'. `left' is synonymous + with 0, and `extreme-right' is synonymous with `(length toolbar)'. + `right' specifies placing a new item at the right end of the + flush-left group of buttons. + + Default value: `right'. Customize type: sexp. + + See also `toolbar-add-button', *Note APIs for Adding and Killing::. + + -- Command: toolbar-add-button-on-the-fly description command label + &optional position locale + Add an button at POSITION to the default toolbar of the selected + window. Returns `t'. + + The return value may change. Tell stephen@xemacs.org what value + you think would be (most) useful. + + DESCRIPTION + A string describing the action, and displayed as help. + + COMMAND + An interactive command (ie, a symbol with an interactive + function definition) implementing the action. + + LABEL + A string used to label the button. + + POSITION + Optional. A position (a non-negative integer, or one of the + symbols `left', `right', or `extreme-right'. + + Default: `right'. + + LOCALE + Optional. A specifier locale, defaulting to the current + buffer. If current-buffer-only is not what you want, and you + don't understand specifier locales, use `global'. It's safe + and probably does what you want. + + -- Command: toolbar-add-kbd-macro mac icon is-file + Add a button invoking a keyboard macro to the toolbar. The button + is added at the end of the left group. + + MAC + A keyboard macro name, or the empty string or nil to use a + copy of the last keyboard macro defined. + + ICON + A string specifying the icon to be used. If IS-FILE is + non-`nil', it is interpreted as the name of an image file, and + searched for using `locate-data-file'. Otherwise it is used + verbatim as a label. + + IS-FILE + Determines the treatment of ICON (q.v.). + + Used interactively, prompts for the macro name MAC and an ICON. + IS-FILE is non-`nil' if a prefix argument was used. + + -- Function: toolbar-add-execute-macro-button + Add a button to the global toolbar to execute the last keyboard + macro. + + Unlike `toolbar-add-kbd-macro', this does not copy the macro. The + macro executed will change with redefinitions. + + Due to a simple implementation, this button will not appear in + buffers with local toolbars if invoked after the toolbar is + installed. If you like this button, it's probably best to invoke + this function in your init file. + + -- Function: toolbar-execute-last-kbd-macro + Toolbar thunk which executes the most recently defined keyboard + macro. + + -- Command: restore-initial-toolbar + Restores the default toolbar defined by `initial-toolbar-spec'. + + There is also a cache of killed buttons in `button-palette'. + + +File: edit-utils.info, Node: The Toolbar Editor, Next: APIs for Adding and Killing, Prev: Adding Buttons on the Fly, Up: The Toolbar Utilities + +39.2 The Toolbar Editor +======================= + +To use `edit-toolbar.el', simply type `M-x edit-toolbar RET'. + + For help on the various commands you can type in a +`edit-toolbar' buffer. To save a modified toolbar type `C-x C-s' in an +`edit-toolbar' buffer. If you want to use a saved toolbar in your +future XEmacs sessions, add the following line of code to your init +file: + + (load "~/.xemacs/.toolbar") + + Here is a table of commands and bindings available in +`edit-toolbar-mode'. These commands are also available from the `Edit +Toolbar' menu. + +`q' + `edit-toolbar-quit': Bury the `edit-toolbar' buffer. + +`p' +`DEL' + `edit-toolbar-previous': Select the previous item (line). + +`n' +`SPC' +`RET' + `edit-toolbar-next': Select the next item (line). + +`?' + `describe-mode': Help. + +`f' + `edit-toolbar-set-function': Set the command for the current + button. + +`h' + `edit-toolbar-set-help': Set the help string for the current + button. + +`a' + `edit-toolbar-add-button': Add a new empty button. + +`2' + `edit-toolbar-add-separator-2D-narrow': Add a new narrow 2D + fixed-width spacer. + +`@' + `edit-toolbar-add-separator-2D-wide': Add a new wide 2D + fixed-width spacer. + +`3' + `edit-toolbar-add-separator-3D-narrow': Add a new narrow 3D + fixed-width spacer. + +`#' + `edit-toolbar-add-separator-3D-wide': Add a new wide 3D + fixed-width spacer. + +`R' + `edit-toolbar-add-separator-right-left': Place the filler + separator, which expands to create a flush-left group of buttons + and spacers and a flush-right group. + +`c' + `edit-toolbar-copy': Copy the selected button. + +`d' + `edit-toolbar-down': Reorder the buttons by moving the selected + button down (to the right on a horizontal toolbar). + +`u' + `edit-toolbar-up': Reorder the buttons by moving the selected + button up (to the left on a horizontal toolbar). + +`k' + `edit-toolbar-kill': Kill the selected button. + +`s' +`C-x C-s' + `edit-toolbar-save': Save the current buffer to + `~/.xemacs/.toolbar' in a format that allows it to be reloaded. + +`r' + `edit-toolbar-restore': Restore the original toolbar (ie, before + this editing session started). + + + +File: edit-utils.info, Node: APIs for Adding and Killing, Next: APIs for Search, Prev: The Toolbar Editor, Up: The Toolbar Utilities + +39.3 APIs for Adding and Killing +================================ + + -- Variable: button-palette + List of buttons cut from toolbars. + + Note this is actually a toolbar descriptor. + + -- Function: toolbar-add-item toolbar-spec item &optional position + Add ITEM to TOOLBAR-SPEC at POSITION, and return TOOLBAR-SPEC. + Uses functions that alter list structure. + + ITEM + A toolbar button or spacer specification (eg, from + `toolbar-new-button' or `toolbar-new-spacer'). + + TOOLBAR-SPEC + A toolbar descriptor (eg, from `toolbar-new-toolbar'). + + POSITION + Optional. A non-negative integer, with 0 being the extreme + left and \(length TOOLBAR-SPEC) the extreme right. The + symbols `left', `right', and `extreme-right' are also + accepted. `left' is synonymous with 0. `right' places ITEM + at the right end of the left group of buttons. + `extreme-right' places ITEM at the extreme right of the + toolbar, creating a right group if one does not exist. + + #### This function does not yet support inserting the group + delimiter nil as an explicit item. + + POSITION may be greater than (length TOOLBAR-SPEC), in which case + it is truncated to (length TOOLBAR-SPEC). Note that `(length + TOOLBAR-SPEC)' is not synonymous with `right' or `extreme-right' + (`extreme-right' will create a right group if it doesn't already + exist). + + -- Function: toolbar-new-button icon-spec command help-string + &optional initially-disabled + Return a checked toolbar button specification. + + ICON-SPEC + A list of glyphs (from `make-glyph'), a glyph, or a string to + use as the button's icon. If a string or single glyph, it + will be used for the button-up glyph. If a list, it may + contain 1 to 6 glyphs, which XEmacs will use for button up, + button down, button disabled, button up with caption, button + down with caption, and button disabled with caption, in that + order. Missing or nil glyphs will be defaulted. (#### + Strings as list elements are not supported but could be.) + + COMMAND + The (interactive) command to invoke when the button is + pressed. + + HELP-STRING + A string briefly describing the command, displayed in the + echo area or as balloon help when the pointer enters the + button. + + INITIALLY-DISABLED + Optional. If non-`nil', specifies that the button should + initially be disabled. + + See `default-toolbar' or the Lispref (*note Toolbars: + (lispref)Toolbars.) for more information. + + -- Function: toolbar-new-spacer style &optional size + Returns a checked toolbar spacer "button". + + STYLE + One of the symbols `2d' or `3d', indicating whether the area + is displayed without shadows (giving it a flat appearance), + or with shadows (giving it a raised, 3-D appearance). There + is no default. #### We may set a default style. Tell + stephen@xemacs.org which you use. + + SIZE + Specifies the length, in pixels, of the blank area. If + omitted, it defaults to a device-specific value (8 pixels for + X devices). + + -- Function: make-toolbar-instantiator &optional toolbar-spec domain + Return a checked toolbar instantiator, a list of vectors. + + TOOLBAR-SPEC + May be a list of buttons (ie, a toolbar descriptor, see + `default-toolbar'), a toolbar specifier object, a symbol whose + value is a toolbar specifier object, or `nil'. If `nil', + returns a null list. If a toolbar specifier object or + variable containing one, the specification for DOMAIN is + used. If non-nil, DOMAIN must be a window, a frame, or a + device, otherwise it defaults to the selected window (see + `specifier-instance'). The list thus generated is checked and + returned. + + If TOOLBAR-SPEC is a list, it is copied; it is safe to pass + other packages' toolbar initializers to this function. + However, you probably do not want to change any of the + objects in the returned specification. They are returned as + is, not copied. + + See `default-toolbar' or the Lispref (*note Toolbars: + (lispref)Toolbars.) for more information. + + -- Function: toolbar-kill-item-pos pos &optional toolbar locale + Kill the item at position POS of TOOLBAR in LOCALE. Killed + buttons are prepended to `button-palette'. + + LOCALE defaults to `global'. If there are multiple specs for + LOCALE, take the first one. + + This function currently does not accept symbolic positions a la + `toolbar-add-item'. Use `toolbar-find-item' to locate whole + buttons and spacers, and `toolbar-find-button' to locate buttons by + characteristics. See also `toolbar-find-button-by-icon', + `toolbar-find-button-by-command', and + `toolbar-find-button-by-help-string'. + + +File: edit-utils.info, Node: APIs for Search, Next: Toolbar Portability, Prev: APIs for Adding and Killing, Up: The Toolbar Utilities + +39.4 APIs for Search +==================== + + -- Function: toolbar-find-button item &optional toolbar locale + Return the position of a button containing ITEM in its + specification. + + ITEM + May specify a button, spacer, icon, command, help string, or + nil. If ITEM is nil, find the separator between the group of + buttons to be left justified, and the group to be right + justified. (Distinctions among the various "search key + types" are somewhat heuristic but are probably reliable + enough to use in library code.) + + TOOLBAR + If non-`nil', search it; otherwise search the default toolbar. + + LOCALE + If non-`nil', get TOOLBAR's descriptor in that locale, + otherwise use the `global' locale. + + -- Function: toolbar-find-item item &optional toolbar locale + Return the position of ITEM, a button, spacer, or nil. TOOLBAR + and LOCALE determine the descriptor to be searched. + + If ITEM is nil, find the separator between the group of buttons to + be left justified, and the group to be right justified. If there + are several matching items, the first is returned. If none is + found, return nil. + + -- Function: toolbar-find-button-by-icon icon &optional toolbar locale + Return the position of a button with icon ICON. ICON must be a + list of glyphs or a symbols whose value is a list of glyphs. + TOOLBAR and LOCALE determine the descriptor to be searched. + + If there are several matching buttons, the first is returned. + + -- Function: toolbar-find-button-by-command cmd &optional toolbar + locale + Return the position of a button invoking command CMD. TOOLBAR and + LOCALE determine the descriptor to be searched. + + If there are several matching buttons, the first is returned. + + -- Function: toolbar-find-button-by-help-string str &optional toolbar + locale + Return the position of a button with help-string STR. TOOLBAR and + LOCALE determine the descriptor to be searched. + + If there are several matching buttons, the first is returned. + This function will not find spacers. + + -- Function: toolbar-find-button-by-element object index toolbar + locale &optional thunk + Return the position of a button containing OBJECT in element + INDEX. TOOLBAR and LOCALE determine the descriptor to be searched. + + Optional argument THUNK is a function of one argument which is + used to normalize OBJECT for comparison. + + If there are several matching buttons, the first is returned. + This function will not find spacers. + + +File: edit-utils.info, Node: Toolbar Portability, Prev: APIs for Search, Up: The Toolbar Utilities + +39.5 Toolbar API Portability to GNU Emacs +========================================= + +The `xemacs-toolbar.el' library provides XEmacs toolbar compatibility +functions for GNU Emacs. + + Third-party maintainers may use the same APIs in GNU Emacs as in +XEmacs. Simply provide this library with your own code, and load it +conditionally: + + (if (featurep 'xemacs) + (require 'toolbar-utils) + (require 'toolbar-utils "xemacs-toolbar")) + + XEmacs features that are not present in GNU Emacs will be ignored, +and various arguments with different semantics will be defaulted +appropriately. + + User commands such as `toolbar-add-kbd-macro' and advanced features +such as the toolbar editor and the button cache are not presently +provided. + + +File: edit-utils.info, Node: foldout, Next: func-menu, Prev: The Toolbar Utilities, Up: Top + +40 Folding Extensions for Outline-Mode +************************************** + +This file provides folding editor extensions for `outline-mode' and +`outline-minor-mode' buffers. What's a "folding editor"? Read on... + + Imagine you're in an `outline-mode' buffer and you've hidden all the +text and subheadings under your level-1 headings. You now want to look +at the stuff hidden under one of these headings. Normally you'd do `C-c +C-e' `(show-entry)' to expose the body or `C-c C-i' to expose the child +(level-2) headings. + + With foldout, you do `C-c C-z' (`foldout-zoom-subtree'). This +exposes the body and child subheadings and narrows the buffer so that +only the level-1 heading, the body and the level-2 headings are +visible. If you now want to look under one of the level-2 headings, +position the cursor on it and do `C-c C-z' again. This exposes the +level-2 body and its level-3 child subheadings and narrows the buffer +again. You can keep on zooming in on successive subheadings as much as +you like. A string in the modeline tells you how deep you've gone. + + When zooming in on a heading you might only want to see the child +subheadings. You do this by specifying a numeric argument: `C-u C-c +C-z'. You can specify the number of levels of children too (c.f. +`show-children'): e.g. `M-2 C-c C-z' exposes two levels of child +subheadings. Alternatively, you might only be interested in the body. +You do this by specifying a negative argument: `M-- C-c C-z'. You can +also cause the whole subtree to be expanded, similar to `C-c C-s' +(`show-subtree'), by specifying a zero argument: `M-0 C-c C-z'. + + While you're zoomed in you can still use outline-mode's exposure and +hiding functions. It won't upset foldout at all. Also, since the +buffer is narrowed, "global" editing actions will only affect the stuff +under the zoomed-in heading. This is useful for restricting changes to +a particular chapter or section of your document. + + You unzoom (exit) a fold by doing `C-c C-x' (`foldout-exit-fold'). +This hides all the text and subheadings under the top-level heading and +returns you to the previous view of the buffer. Specifying a numeric +argument exits that many folds. Specifying a zero argument exits *all* +folds. + + You might want to exit a fold *without* hiding the text and +subheadings. You do this by specifying a negative argument. For +example, `M--2 C-c C-x' exits two folds and leaves the text and +subheadings exposed. + + Foldout also provides mouse bindings for entering and exiting folds +and for showing and hiding text. Hold down Meta and Control, then +click a mouse button as follows:- + + * mouse-1 (`foldout-mouse-zoom') zooms in on the heading clicked on: + + - single click - expose body + + - double click - expose subheadings + + - triple click - expose body and subheadings + + - quad click - expose entire subtree + + + * mouse-2 (`foldout-mouse-show') exposes text under the heading + clicked on: + + - single click - expose body + + - double click - expose subheadings + + - triple click - expose body and subheadings + + - quad click - expose entire subtree + + + * mouse-3 (`foldout-mouse-hide-or-exit') hides text under the + heading clicked on or exits the fold: + + - single click - hide subtree + + - double click - exit fold and hide text + + - triple click - exit fold without hiding text + + - quad click - exit all folds and hide text + + + + You can change the modifier keys used by setting +`foldout-mouse-modifiers'. + + To use foldout, put this in your initialization file: + + (require 'foldout) + + If you don't want it loaded until you need it, try this instead: + + (eval-after-load "outline" '(require 'foldout)) + + +File: edit-utils.info, Node: func-menu, Next: id-select, Prev: foldout, Up: Top + +41 Jump to a Function Within a Buffer. +************************************** + +Suppose you have a file with a lot of functions in it. Well, this +package makes it easy to jump to any of those functions. The names of +the functions in the current buffer are automatically put into a +menubar menu, you select one of the function-names and the point is +moved to that very function. The mark is pushed on the mark-ring, so +you can easily go back to where you were. Alternatively, you can use +enter the name of the desired function via the minibuffer which offers +completing read input. In addition, the name of the function before +point is optionally displayed in the modeline. + + The following modes are supported: + + Ada, Assembly, BibTex, C++, C, Dired, Ehdm, ELisp, FORTRAN, Ksh, +Latex, Lelisp, Makefile, Maple, Modula2, Modula3, Outline, Objective-C, +Pascal, Perl, Postscript, Prolog, PVS, Python, SGML, Scheme, Tcl, +Verilog, Manual, Ruby, JavaScript + + To install this package, add the following to your initialization +file: + + (add-hook 'find-file-hooks 'fume-setup-buffer) + (add-hook 'Manual-mode-hook 'turn-on-fume-mode) + + +File: edit-utils.info, Node: id-select, Next: outl-mouse, Prev: func-menu, Up: Top + +42 Select Syntax-Driven Regions in a Buffer +******************************************* + +This is a radically cool, drop in mouse and keyboard-based library for +selecting successively bigger syntactical regions within a buffer. +Simply load this library and you are ready to try it out by +double-clicking on various kinds of characters in different buffer +major modes. You'll quickly get the hang of it. (It also provides a +command to jump between beginning and end tags within HTML and SGML +buffers.) + + A great deal of smarts are built-in so that it does the right thing +almost all of the time; many other attempts at similar behavior such as +`thing.el' fail to deal with many file format complexities. + + Double clicks of the Selection Key (left mouse key) at the same +point will select bigger and bigger regions with each successive use. +The first double click selects a region based upon the character at the +point of the click. For example, with the point over an opening or +closing grouping character, such as { or }, the whole grouping is +selected, e.g. a C function. When on an _ or - within a programming +language variable name, the whole name is selected. The type of +selection is displayed in the minibuffer as feedback. When using a +language based mainly on indenting, like Bourne shell, a double click +on the first alpha character of a line, such as an if statement, +selects the whole statement. + + This whole package is driven by a single function, available in +mouse and keyboard forms, that first marks a region based on the syntax +category of the character following point. Successive invocations mark +larger and larger regions until the whole buffer is marked. See the +documentation for the function, `id-select-syntactical-region', for the +kinds of syntax categories handled. + + Loading this package automatically installs its functionality on +double-clicks (or higher) of the left mouse key. (See the +documentation for the variable, `mouse-track-click-hook', for how this +is done.) A single click of the left button will remove the region and +reset point. + + The function, `id-select-thing', may be bound to a key to provide the +same syntax-driven region selection functionality. `C-c C-m' is a +reasonable site-wide choice since this key is seldom used and it +mnemonically indicates marking something. `C-c s' may be preferred as +a personal binding. + + Use `C-g' to unmark the region when done. Use, +`id-select-thing-with-mouse', if you want to bind this to a mouse key +and thereby use single clicks instead of double clicks. + + Three other commands are also provided: + +`id-select-and-copy-thing' + mark and copy the syntactical unit to the kill ring + +`id-select-and-kill-thing' + kill the syntactical unit at point + +`id-select-goto-matching-tag' + In HTML and SGML modes (actually any listed in the variable, + `id-select-markup-modes'), moves point to the start of the tag + paired with the closest tag that point is within or which it + precedes, so you can quickly jump back and forth between open and + close tags. + + + To autoload this package via mouse usage, add the following line to +one of your initialization files: + + (add-hook 'mouse-track-click-hook 'id-select-double-click-hook) + + To configure this package, type: + + M-x customize-group RET id-select RET + + +File: edit-utils.info, Node: outl-mouse, Next: page-ext, Prev: id-select, Up: Top + +43 Outline-Mode Mouse Commands +****************************** + +Defines `mouse button one' to hide blocks when clicked on +outline-up-arrow and expand blocks when clicked on outline-down-arrow. +Features are activated when `outline-minor-mode' or `outline-mode' are +turned on. There is also a menu for each glyph on `mouse button 3'. + + To use, add the following to your initialization file: + + (require 'outl-mouse) + + If you use func-menu all the time and want outl-mouse on all the +time as well then specify `(setq outline-sync-with-func-menu t)'. +Outlining will then be turned on when func-menu is activated. + + If you want mac-style outlining then set `outline-mac-style' to t. +If you want the outline arrows on the left then set +`outline-glyphs-on-left' to t. If you have xpm then arrows are much +better defined. + + To configure this package, type: + + M-x customize-group RET outl-mouse RET + + +File: edit-utils.info, Node: page-ext, Next: power-macros, Prev: outl-mouse, Up: Top + +44 Extended Page Handling Commands +********************************** + +The page commands are helpful in several different contexts. For +example, programmers often divide source files into sections using the +`page-delimiter'; you can use the `pages-directory' command to list the +sections. + + You may use the page commands to handle an address list or other +small data base. Put each address or entry on its own page. The first +line of text in each page is a `header line' and is listed by the +`pages-directory' or `pages-directory-for-addresses' command. + +* Menu: + +* Key Assignments: page-ext-keys. +* Using the Page Commands: page-ext-using. +* Address List or Small Database: page-ext-addr. + + +File: edit-utils.info, Node: page-ext-keys, Next: page-ext-using, Prev: page-ext, Up: page-ext + +44.1 Key Assignments +==================== + +The current page commands are: + +forward-page C-x ] +backward-page C-x [ +narrow-to-page C-x p +count-lines-page C-x l +mark-page C-x C-p (change this to C-x C-p C-m) +sort-pages not bound +what-page not bound + + The new page handling commands all use `C-x C-p' as a prefix. This +means that the key binding for `mark-page' must be changed. Otherwise, +no other changes are made to the current commands or their bindings. + + The extended page handling commands are: + +next-page C-x C-p C-n +previous-page C-x C-p C-p +search-pages C-x C-p C-s +add-new-page C-x C-p C-a +sort-pages-buffer C-x C-p s +set-page-delimiter C-x C-p C-l +pages-directory C-x C-p C-d +pages-directory-for-addresses C-x C-p d +pages-directory-goto C-c C-c + + +File: edit-utils.info, Node: page-ext-using, Next: page-ext-addr, Prev: page-ext-keys, Up: page-ext + +44.2 Using the Page Commands +============================ + +The page commands are helpful in several different contexts. For +example, programmers often divide source files into sections using the +`page-delimiter'; you can use the `pages-directory' command to list the +sections. + + You may change the buffer local value of the `page-delimiter' with +the `set-page-delimiter' command. This command is bound to `C-x C-p +C-l'. The command prompts you for a new value for the `page-delimiter'. +Called with a prefix-arg, the command resets the value of the +page-delimiter to its original value. + + You may set several user options: + +`pages-directory-buffer-narrowing-p' + Causes the `pages-directory-goto' command to narrow to the + destination page. + +`pages-directory-for-adding-page-narrowing-p' + Causes the `add-new-page' command to narrow to the new entry. + +`pages-directory-for-adding-new-page-before-current-page-p' + Causes the `add-new-page' command to insert a new page before + current page. + + + These variables are all true by default. + + +File: edit-utils.info, Node: page-ext-addr, Prev: page-ext-using, Up: page-ext + +44.3 Address List or Small Database +=================================== + +You may use the page commands to handle an address list or other small +data base. Put each address or entry on its own page. The first line +of text in each page is a `header line' and is listed by the +`pages-directory' or `pages-directory-for-addresses' command. + + Specifically: + + 1. Begin each entry with a `page-delimiter' (which is, by default, + `^L' at the beginning of the line). + + 2. The first line of text in each entry is the `heading line'; it + will appear in the pages-directory-buffer which is constructed + using the `C-x C-p C-d' (`pages-directory') command or the `C-x + C-p d' (`pages-directory-for-addresses') command. + + The heading line may be on the same line as the page-delimiter or + it may follow after. It is the first non-blank line on the page. + Conventionally, the heading line is placed on the line immediately + following the line containing page-delimiter. + + 3. Follow the heading line with the body of the entry. The body + extends up to the next `page-delimiter'. The body may be of any + length. It is conventional to place a blank line after the last + line of the body. + + + For example, a file might look like this: + + FSF + Free Software Foundation + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 USA. + (617) 542-5942 + gnu@prep.ai.mit.edu + + + House Subcommittee on Intellectual Property, + U.S. House of Representatives, + Washington, DC 20515 + + Congressional committee concerned with permitting or preventing + monopolistic restrictions on the use of software technology. + + + George Lakoff + ``Women, Fire, and Dangerous Things: + What Categories Reveal about the Mind'' + 1987, Univ. of Chicago Press + + About philosophy, Whorfian effects, and linguistics. + + + OBI (On line text collection.) + Open Book Initiative + c/o Software Tool & Die + 1330 Beacon St, Brookline, MA 02146 USA + (617) 739-0202 + obi@world.std.com + + In this example, the heading lines are: + + FSF + House Subcommittee on Intellectual Property + George Lakoff + OBI (On line text collection.) + + The `C-x C-p s' (`sort-pages-buffer') command sorts the entries in +the buffer alphabetically. + + You may use any of the page commands, including the `next-page', +`previous-page', `add-new-page', `mark-page', and `search-pages' +commands. + + You may use either the `C-x C-p d' (`pages-directory-for-addresses') +or the `C-x C-p C-d' (`pages-directory') command to construct and +display a directory of all the heading lines. + + In the directory, you may position the cursor over a heading line +and type `C-c C-c' (`pages-directory-goto') to go to the entry to which +it refers in the pages buffer. + + You can type `C-c C-p C-a' (`add-new-page') to add a new entry in +the pages buffer or address file. This is the same command you use to +add a new entry when you are in the pages buffer or address file. + + If you wish, you may create several different directories, one for +each different buffer. + + ``pages-directory-for-addresses' assumes a default addresses file. +You do not need to specify the addresses file but merely type `C-x C-p +d' from any buffer. The command finds the file, constructs a directory +for it, and switches you to the directory. If you call the command +with a prefix arg, `C-u C-x C-p d', it prompts you for a file name. + + You may customize the addresses commands: + +`pages-addresses-file-name' + Determines the name of the addresses file; by default it is + "~/addresses". + +`pages-directory-for-addresses-goto-narrowing-p' + Determines whether `pages-directory-goto' narrows the addresses + buffer to the entry, which it does by default. + +`pages-directory-for-addresses-buffer-keep-windows-p' + Determines whether `pages-directory-for-addresses' deletes other + windows to show as many lines as possible on the screen or works + in the usual Emacs manner and keeps other windows. Default is to + keep other windows. + +`pages-directory-for-adding-addresses-narrowing-p' + Determines whether `pages-directory-for-addresses' narrows the + addresses buffer to a new entry when you are adding that entry. + Default is to narrow to new entry, which means you see a blank + screen before you write the new entry. + + + Call the `pages-directory' command from the buffer for which you +want a directory created; it creates a directory for the buffer and +pops you to the directory. + + The `pages-directory' command has several options: + + 1. Called with a prefix arg, `C-u C-x C-p C-d', the `pages-directory' + prompts you for a regular expression and only lists only those + header lines that are part of pages that contain matches to the + regexp. In the example above, `C-u C-x C-p C-d 617 RET' would + match the telephone area code of the first and fourth entries, so + only the header lines of those two entries would appear in the + pages-directory-buffer. + + 2. Called with a numeric argument, the `pages-directory' command + lists the number of lines in each page. This is helpful when you + are printing hardcopy. + + 3. Called with a negative numeric argument, the `pages-directory' + command lists the lengths of pages whose contents match a regexp. + + + To configure this package, type: + + M-x customize-group RET pages RET + + +File: edit-utils.info, Node: power-macros, Next: redo, Prev: page-ext, Up: Top + +45 Power Macros - Keyboard Macros Made Easy +******************************************* + +Keyboard Macros are a very powerful tool, if you know how to use them +the right way! Without this extension it is, however, a bit difficult +in Emacs to define and maintain several macros at a time. This problem +is solved with this package. + + When you have loaded this package Emacs will, upon completion of +macro definition, ask you which key you want to assign this macro to +and ask for a description of the macro. If something is already bound +to this key, Emacs will ask you whether you want to override this +binding. Furthermore, this package also takes care of saving the macro +to your initialization file for later Emacs sessions. + + The description for all the defined macros may be obtained with the +function `pm-manage-macros'. Using this function you can also manage +your power-macros. + + To execute this function, type: + + M-x pm-manage-macros RET + + To configure the package, type: + + M-x customize-group RET power-macros RET + + +File: edit-utils.info, Node: redo, Next: scroll-in-place, Prev: power-macros, Up: Top + +46 Redo/Undo System +******************* + +Emacs' normal undo system allows you to undo an arbitrary number of +buffer changes. These undos are recorded as ordinary buffer changes +themselves. So when you break the chain of undos by issuing some other +command, you can then undo all the undos. The chain of recorded buffer +modifications therefore grows without bound, truncated only at garbage +collection time. + + The redo/undo system is different in two ways: + + 1. The undo/redo command chain is only broken by a buffer + modification. You can move around the buffer or switch buffers + and still come back and do more undos or redos. + + 2. The `redo' command rescinds the most recent undo without + recording the change as a _new_ buffer change. It completely + reverses the effect of the undo, which includes making the chain + of buffer modification records shorter by one, to counteract the + effect of the undo command making the record list longer by one. + + + To use this package, add the following to your initialization file: + + (require 'redo) + + +File: edit-utils.info, Node: scroll-in-place, Next: setnu, Prev: redo, Up: Top + +47 Scrolling In Place +********************* + +This library provides improved vertical scrolling commands for GNU +Emacs. + +* Menu: + +* Features: sip-features. +* Commands and Functions: sip-commands. +* Installation: sip-install. +* Advanced Customization: sip-customize + + +File: edit-utils.info, Node: sip-features, Next: sip-commands, Prev: scroll-in-place, Up: scroll-in-place + +47.1 Features +============= + +The new vertical scrolling commands offer the following features: + + * When a scrolling command is executed, GNU Emacs tries to keep + point as close as possible to its original window position (window + line and column). This is what "scroll in place" means: point + stays "in place" within the window. (There are times when point + must be moved from its original window position in order to + execute the scroll; see below.) + + The variable `scroll-in-place', which is true by default, + determines whether or not the standard GNU Emacs scrolling + commands (`scroll-down', `scroll-up', `scroll-other-window-down', + and `scroll-other-window') use the "in place" features listed + here. When `scroll-in-place' is nil the standard GNU Emacs + scrolling commands essentially just call the original versions of + themselves. (Note that even when `scroll-in-place' is nil the new + versions of `scroll-down' and `scroll-up' have slightly different + behavior when a minibuffer window is the selected window. See + below.) + + It is possible to turn off (or turn on) "in place" scrolling for + certain buffers by making buffer-local bindings of the variable + `scroll-in-place' for those buffers. The variable + `scroll-in-place' is not usually buffer-local, but you can make it + so if you desire. + + * Because the improved scrolling commands keep point at its + original window position, these scrolling commands are + "reversible." The `scroll-up' command undoes the effect of the + immediately previous `scroll-down' command (if any) and vice + versa. In other words, if you scroll up and then immediately + scroll back down, the window configuration is restored to its + exact original state. This allows you to browse through a buffer + more easily, as you can always get back to the original + configuration. + + Note, however, that the improved scrolling commands are guaranteed + to be reversible only if there are no intervening non-scrolling + commands. Also, if you give a prefix argument to a scrolling + command (in order to specify the number of lines to scroll by), + previous scrolling commands may no longer be reversible. More + specifically, if the new prefix argument has a different magnitude + than the previous scrolling distance, then any previous scrolling + commands are not reversible. The new prefix argument takes + precedence. + + You might find it useful to think of the scrolling commands as + forming "chains." A scrolling command either starts or continues + a chain. By issuing a non-scrolling command or by changing the + number of lines to be scrolled, you break the chain. (Note that + simply changing the scrolling direction won't break the chain; + changing the absolute number of lines to be scrolled is what + breaks the chain.) Scrolling commands are guaranteed to be + reversible only within the current chain. Hopefully that's clear + enough. + + * When a scrolling command is given a prefix argument (which + specifies the number of lines to scroll by), then that argument + becomes the default scrolling distance for all immediately + subsequent scrolling commands. This means that you can easily set + the scrolling distance for a chain of scrolling commands. Note + that a new prefix argument or any non- scrolling command breaks + the chain (as described above), and any further scrolling commands + will use the usual defaults (or the prefix argument you specify at + that time, of course). + + However, there are cases in which one doesn't want the current + scrolling command to use the default scrolling distance that was + set by the previous scrolling command. For example, suppose that + you had special commands that scrolled one line up and one line + down. When you invoke one of these commands, the "in place" + scrolling routines set the default scrolling distance to be just + one line. Now suppose that you use one of your special commands + and then immediately invoke `scroll-up' (`C-v'), expecting it to + scroll by a near windowful of text. You would be disappointed -- + because the previous command set the default scrolling distance to + be just one line, `scroll-up' just scrolls by one line. + + To solve this problem, "scroll-in-place" allows you to divide + scrolling commands into separate "groups." Commands in a group + can only form chains with (and therefore, inherit defaults from) + commands in the same group. (Note that no command can be in more + than one group.) If you invoke a scrolling command that is not in + the same group as that of the immediately previous scrolling + command, then the previous chain is broken and you start a new + chain -- with a new set of defaults. + + So to solve the problem described above, you could put your + one-line scrolling commands in their own group. Once that is + done, the standard scrolling commands will not form chains with + your one-line scrolling commands, and therefore will not use the + default scrolling distance set by those commands. Problem solved! + + By default, all "in place" scrolling commands are in a single + group. If you want to partition some commands into separate + groups, you must do that yourself _before_ any "in place" commands + are invoked. For more information about grouping commands, see + the documentation for the variables `scroll-command-groups' and + `scroll-default-command-group'. + + * The improved scrolling commands will avoid displaying empty lines + past the end of the buffer when possible. In other words, just as + you can't see "dead space" before the beginning of the buffer + text, the new scrolling commands try to avoid displaying "dead + space" past the end of the buffer text. This behavior is somewhat + configurable; see the documentation for the variable + `scroll-allow-blank-lines-past-eob'. + + Dead space will be displayed if it is necessary in order to make a + previous scrolling action reversible, however. + + * If the scrolling commands cannot keep point at its initial window + position (because a buffer boundary is on screen and the window + can't be scrolled as far as necessary to keep point at the right + place), point is allowed to temporarily stray from its initial + window position. That is, point moves the correct number of + window lines, even if it means that it has to stray from its + desired window position. This straying is undone when (and if) the + scrolling action is reversed. + + * If a scrolling command tries to move point past a buffer + boundary, point is instead moved to the boundary (the beginning or + the end of the buffer as appropriate) and an appropriate message + is displayed. This motion is reversible, of course. + + However, if point was already at the buffer boundary when the + scrolling command was invoked, the command signals an appropriate + error instead. + + * When a minibuffer window is the selected window, the new versions + of `scroll-up' and `scroll-down' either scroll the window in the + variable `minibuffer-scroll-window' (which is usually the window of + completions) or the `next-window' if there is no + `minibuffer-scroll-window'. This is usually much more useful than + scrolling the minibuffer itself. (Note that this feature is + available even when the variable `scroll-in-place' is nil.) + + * When a scrolling command is scrolling a window other than the + selected window, it will signal an appropriate buffer boundary + error if the window cannot be scrolled (because the appropriate + buffer boundary is already visible). This means that an error is + signalled even in cases that would be allowed (by "straying" point + or by moving it to the buffer boundary) if the window were + selected. + + (If an error were not signalled in these cases, then there would + be many cases in which the last scroll in a particular direction + would appear to do nothing because only the point position would + change -- the displayed text would stay the same! To avoid these + cases the scrolling commands signal boundary errors "prematurely" + when the window to be scrolled is not selected.) + + + +File: edit-utils.info, Node: sip-commands, Next: sip-install, Prev: sip-features, Up: scroll-in-place + +47.2 Command and Functions +========================== + +This library provides the following "in place" versions of GNU Emacs' +standard vertical scrolling commands: + + * scroll-down-in-place + + * scroll-up-in-place + + * scroll-other-window-down-in-place + + * scroll-other-window-in-place + + The variable `scroll-in-place', which is true by default, determines +whether or not the new versions of the standard GNU Emacs scrolling +commands (`scroll-down', `scroll-up', `scroll-other-window-down', and +`scroll-other-window') use the "in place" features listed above. When +`scroll-in-place' is nil the standard GNU Emacs scrolling commands +essentially just call the original versions of themselves. (Note that +even when `scroll-in-place' is nil the new versions of `scroll-down' and +`scroll-up' have slightly different behavior when a minibuffer window is +the selected window. See the feature list above.) + + NOTE that this package redefines the standard GNU Emacs commands +`scroll-down', `scroll-up', `scroll-other-window-down', and +`scroll-other-window' (in order to check the variable +`scroll-in-place', as described above). The command +`scroll-other-window-down' first appeared as a standard command in the +FSF's GNU Emacs 19.26. + + This package also provides the following functions and variables +which are of use to programmers: + + * scroll-window + + * scroll-window-in-place + + * scroll-window-in-place-continue-sequence + + * scroll-default-lines (variable) + + * scroll-command-groups (variable) + + The `scroll-window-in-place' function is the heart of the "in place" +scrolling commands. `scroll-window' is a function that checks the +variable `scroll-in-place' and calls the appropriate scrolling function +(either `scroll-window-in-place' or one of the original versions of +`scroll-down' and `scroll-up'). The function +`scroll-window-in-place-continue-sequence' is provided in order to +preserve running "chains" of scrolling commands as described above. + + The variable `scroll-default-lines' determines the default scrolling +distance when a new chain of "in place" scrolling commands begins. If +this variable is not a number, then the default distance is the height +of the window to be scrolled minus `next-screen-context-lines'. The +variable `scroll-command-groups' contains the explicit groups of "in +place" scrolling commands; for more information read the variable +documentation. + + +File: edit-utils.info, Node: sip-install, Next: sip-customize, Prev: sip-commands, Up: scroll-in-place + +47.3 Installation +================= + +To use this package, you simply need to load it from within your +initialization file: + + (require 'scroll-in-place) + + By default, this package provides for the standard GNU Emacs vertical +scrolling commands (`scroll-down', `scroll-up', +`scroll-other-window-down', and `scroll-other-window') to use the "in +place" features. If you would rather not have this, set the variable +`(setq scroll-in-place nil)'. + + When `scroll-in-place' is nil you will have to bind keys in order to +call the "in place" scrolling commands. For example, you might want to +do the following: + + (global-set-key "\M-v" 'scroll-down-in-place) + (global-set-key "\C-v" 'scroll-up-in-place) + + +File: edit-utils.info, Node: sip-customize, Prev: sip-install, Up: scroll-in-place + +47.4 Advanced Customization +=========================== + +If you want to partition certain "in place" scrolling commands into +separate groups, you should do something like the following: + + ;; Make one group containing the commands `scroll-down-one-line' and + ;; `scroll-up-one-line'. (These are not standard GNU Emacs commands.) + (setq scroll-command-groups + (list '(scroll-down-one-line scroll-up-one-line))) + + You could write the `scroll-down-one-line' command like this: + + (defun scroll-down-one-line (arg) + "Scroll down one line, or number of lines specified by prefix arg." + (interactive "P") + (let ((scroll-default-lines 1)) + (scroll-down-in-place arg))) + + If you want to disable "in place" scrolling for windows that display +a particular buffer (while leaving it available in other windows), you +can make `scroll-in-place' a buffer-local variable for that buffer and +then bind that local copy of `scroll-in-place' to nil. This is the +kind of thing that one generally does in a major mode hook. For +example, you can disable "in place" scrolling of GNUS article windows +with the following code: + + (setq gnus-article-mode-hook + (function (lambda () + (make-local-variable 'scroll-in-place) + (setq scroll-in-place nil)))) + ;; Set the variable `gnus-Article-mode-hook' instead if you are using + ;; an old version of GNUS, say version 3.13 or 3.14. + + The variable `scroll-allow-blank-lines-past-eob' can also be made +local to particular buffers, if you desire. (But why would you want to +do that?) + + +File: edit-utils.info, Node: setnu, Next: vertical-mode, Prev: scroll-in-place, Up: Top + +48 VI-style Line Number Mode +**************************** + +This library activates VI-style line numbering for a buffer. + + `M-x setnu-mode' toggles the line number mode on and off. + + `turn-on-setnu-mode' is useful for adding to a major-mode hook +variable. + + (add-hook 'text-mode-hook 'turn-on-setnu-mode) + + to automatically turn on line numbering when entering text-mode. + + +File: edit-utils.info, Node: vertical-mode, Next: align, Prev: setnu, Up: Top + +49 Vertical Mode - Editing of Vertical Text +******************************************* + +This minor mode allows you to conveniently edit things that are oriented +vertically (like tables in computer programs): after each action, cursor +moves down. Therefore, to move block of text to the right, you simply +enter vertical mode and then hold `spacebar', waiting for autorepeat to +do the job for you. + + +File: edit-utils.info, Node: align, Next: allout, Prev: vertical-mode, Up: Top + +50 Align Text to a Specific Column, By Regexp +********************************************* + +This mode allows you to align regions in a context-sensitive fashion. +The classic use is to align assignments: + + int a = 1; + short foo = 2; + double blah = 4; + + becomes + + int a = 1; + short foo = 2; + double blah = 4; + +* Menu: + +* Align Usage:: How to use the package. + + +File: edit-utils.info, Node: Align Usage, Prev: align, Up: align + +50.1 Align Usage +================ + +To configure the package, type: + + M-x customize-group RET align RET + + There are several variables which define how certain "categories" of +syntax are to be treated. These variables go by the name +`align-CATEGORY-modes'. For example, "c++" is such a category. There +are several rules which apply to c++, but since several other languages +have a syntax similar to c++ (e.g., c, java, etc), these modes are +treated as belonging to the same category. + + If you want to add a new mode under a certain category, just +customize that list, or add the new mode manually. For example, to +make jde-mode a c++ category mode, use this code in your initialization +file: + + (setq align-c++-modes (cons 'jde-mode align-c++-modes)) + + In some programming modes, it's useful to have the aligner run only +after indentation is performed. To achieve this, customize or set the +variable `align-indent-before-aligning' to t. + + +File: edit-utils.info, Node: allout, Next: narrow-stack, Prev: align, Up: Top + +51 Extensive Outline Mode +************************* + +Allout outline mode provides extensive outline formatting and +manipulation beyond standard emacs outline mode (*note Outline Mode: +(xemacs)Outline Mode.). It provides for structured editing of +outlines, as well as navigation and exposure. It also provides for +syntax-sensitive text like programming languages. (For an example, see +the allout code itself, which is organized in ;; an outline framework.) + + In addition to outline navigation and exposure, allout includes: + + * topic-oriented repositioning, cut, and paste + + * integral outline exposure-layout + + * incremental search with dynamic exposure and reconcealment of + hidden text + + * automatic topic-number maintenance + + * "Hot-spot" operation, for single-keystroke maneuvering and exposure + control. (See the outline-mode docstring.) + + + and many other features. + + To configure the package, type: + + M-x customize-group RET allout RET + + To use the allout package in place of the standard outline package, +add the following bit of code + + (require 'outline "allout") + + to your initialization file. This will ensure that all the functions +provided by the outline package will be loaded from the new allout +package instead. + + The outline menubar additions provide quick reference to many of the +features, and see the docstring of the variable `outline-init' for +instructions on priming your emacs session for automatic activation of +outline-mode. + + See the docstring of the variables `outline-layout' and +`outline-auto-activation' for details on automatic activation of allout +outline-mode as a minor mode. + + By default, allout mode does not fontify the buffer. To get Font +Lock to work put the following into your initialization file (adapted +from the standard outline mode): + + (defvar rf-allout-font-lock-keywords + '(;; + ;; Highlight headings according to the level. + (eval . (list (concat "^\\(" outline-regexp "\\).+") + 0 '(or (cdr (assq (outline-depth) + '((1 . font-lock-function-name-face) + (2 . font-lock-variable-name-face) + (3 . font-lock-keyword-face) + (4 . font-lock-builtin-face) + (5 . font-lock-comment-face) + (6 . font-lock-constant-face) + (7 . font-lock-type-face) + (8 . font-lock-string-face)))) + font-lock-warning-face) + nil t))) + "Additional expressions to highlight in Outline mode.") + + ;; add font-lock to allout mode + (defun rf-allout-font-lock-hook () + (set (make-local-variable 'font-lock-defaults) + '(rf-allout-font-lock-keywords t nil nil outline-back-to-current-heading))) + + (add-hook 'outline-mode-hook 'rf-allout-font-lock-hook) + + +File: edit-utils.info, Node: narrow-stack, Next: flow-ctrl, Prev: allout, Up: Top + +52 Extending the built-in narrowing functions +********************************************* + +Narrowing, as implemented in Emacs has one limitation, namely that it +is not possible to narrow within a narrowing, and then widen again to +the previous narrowing. This package implements an extension to +narrowing, which makes this possible. + + To activate this extension type `M-x narrow-stack-mode' or add +`(narrow-stack-mode)' to your initialization file. + + +File: edit-utils.info, Node: flow-ctrl, Next: makesum, Prev: narrow-stack, Up: Top + +53 Flow Control +*************** + +Terminals that use XON/XOFF flow control can cause problems with GNU +Emacs users. This file contains Emacs Lisp code that makes it easy for +a user to deal with this problem, when using such a terminal. + + To invoke these adjustments, a user need only invoke the function +`enable-flow-control-on' with a list of terminal types specified in the +initialization file. As arguments, give it the names of one or more +terminal types in use by that user which require flow control +adjustments. Here's an example: + + (enable-flow-control-on "vt200" "vt300" "vt101" "vt131") + + Portability note: This uses `(getenv "TERM")', and therefore probably +won't work outside of UNIX-like environments. + + +File: edit-utils.info, Node: makesum, Next: man, Prev: flow-ctrl, Up: Top + +54 Generate Summary of All Key Binding +************************************** + +Displays a nice human-readable summary of all keybindings in a +two-column format. + + To invoke this command, type: + + M-x make-command-summary RET + + +File: edit-utils.info, Node: man, Next: abbrevlist, Prev: makesum, Up: Top + +55 Browse UNIX manual pages +*************************** + +This library defines the command `manual-entry' to browse Unix manual +pages. + + To invoke this command, type: + + M-x manual-entry RET + + For ease of use, autocompletion on `M-x man' will work just fine. + + To configure this package, type: + + M-x customize-group RET man RET + + +File: edit-utils.info, Node: abbrevlist, Next: file-part, Prev: man, Up: Top + +56 Abbreviation List +******************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: file-part, Next: info-look, Prev: abbrevlist, Up: Top + +57 Treat a Section of a Buffer as a Separate File +************************************************* + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: info-look, Next: live-icon, Prev: file-part, Up: Top + +58 Major-Mode-Sensitive Info Index Lookup Facility +************************************************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: live-icon, Next: mode-motion+, Prev: info-look, Up: Top + +59 Make Frame Icons Represent Current Frame Contents +**************************************************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: mode-motion+, Next: popper, Prev: live-icon, Up: Top + +60 Per Mode/Buffer Mouse Tracking With Highlighting +*************************************************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: popper, Next: reportmail, Prev: mode-motion+, Up: Top + +61 Shrink-Wrapped Temporary Windows +*********************************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: reportmail, Next: balloon-help, Prev: popper, Up: Top + +62 Display Time and Load in Mode Line +************************************* + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: balloon-help, Next: blink-paren, Prev: reportmail, Up: Top + +63 Balloon Help and Tooltips +**************************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: blink-paren, Next: edit-faces, Prev: balloon-help, Up: Top + +64 Blinking Parentheses +*********************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: edit-faces, Next: lispm-fonts, Prev: blink-paren, Up: Top + +65 Face Editor +************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: lispm-fonts, Next: big-menubar, Prev: edit-faces, Up: Top + +66 lispm-fonts +************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: big-menubar, Next: tree-menu, Prev: lispm-fonts, Up: Top + +67 Big Menubar +************** + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: tree-menu, Next: XEmacs License, Prev: big-menubar, Up: Top + +68 tree-menu +************ + +This library not documented. Please contribute! + + +File: edit-utils.info, Node: XEmacs License, Prev: tree-menu, Up: Top + +69 XEmacs License +***************** + +GNU GENERAL PUBLIC LICENSE +************************** + + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble +======== + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", + below, refers to any such program or work, and a "work based on + the Program" means either the Program or any derivative work under + copyright law: that is to say, a work containing the Program or a + portion of it, either verbatim or with modifications and/or + translated into another language. (Hereinafter, translation is + included without limitation in the term "modification".) Each + licensee is addressed as "you". + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running the Program is not restricted, and the output from the + Program is covered only if its contents constitute a work based on + the Program (independent of having been made by running the + Program). Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any + warranty; and give any other recipients of the Program a copy of + this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b. You must cause any work that you distribute or publish, that + in whole or in part contains or is derived from the Program + or any part thereof, to be licensed as a whole at no charge + to all third parties under the terms of this License. + + c. If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display + an announcement including an appropriate copyright notice and + a notice that there is no warranty (or else, saying that you + provide a warranty) and that users may redistribute the + program under these conditions, and telling the user how to + view a copy of this License. (Exception: if the Program + itself is interactive but does not normally print such an + announcement, your work based on the Program is not required + to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Program, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Program, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Program. + + In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you also do one of the + following: + + a. Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Sections 1 and 2 above on a medium customarily used for + software interchange; or, + + b. Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or, + + c. Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with + such an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete + source code means all the source code for all modules it contains, + plus any associated interface definition files, plus the scripts + used to control compilation and installation of the executable. + However, as a special exception, the source code distributed need + not include anything that is normally distributed (in either + source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable + runs, unless that component itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Program or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Program (or any work + based on the Program), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program + subject to these terms and conditions. You may not impose any + further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Program at all. For example, if a patent license would not permit + royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Program under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 9. The Free Software Foundation may publish revised and/or new + versions of the General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Program + does not specify a version number of this License, you may choose + any version ever published by the Free Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the + author to ask for permission. For software which is copyrighted + by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision + will be guided by the two goals of preserving the free status of + all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY + OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) 19YY NAME OF AUTHOR + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Also add information on how to contact you by electronic and paper +mail. + + If the program is interactive, make it output a short notice like +this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + + The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + SIGNATURE OF TY COON, 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Library General Public License instead of this License. + + + +Tag Table: +Node: Top927 +Node: Copying5753 +Node: compare-w9903 +Node: detached-minibuf10300 +Node: iswitchb10596 +Node: iswitchb-cust13966 +Node: Changing the Display14675 +Node: Regexp Matching16218 +Node: Replacement for read-buffer17017 +Node: permanent-buffers17600 +Node: rsz-minibuf18623 +Node: search-buffers19715 +Node: uniquify20406 +Node: winring21170 +Node: History24482 +Node: Related Packages25554 +Node: autorevert26712 +Node: Auto-Revert Usage27736 +Node: backup-dir28651 +Node: bookmark31054 +Node: desktop31477 +Node: recent-files34353 +Node: recentf-cust36586 +Node: resume41256 +Node: saveconf41463 +Node: savehist42989 +Node: saveplace43765 +Node: where-was-i-db44400 +Node: completion49021 +Node: dabbrev50464 +Node: hippie-exp51039 +Node: icomplete55976 +Node: tempo57138 +Node: avoid59682 +Node: blink-cursor60969 +Node: fast-lock61249 +Node: lazy-lock62266 +Node: lazy-shot63510 +Node: mic-paren64386 +Node: paren67548 +Node: shell-font68779 +Node: highline69280 +Node: highline-keys70357 +Node: highline-hooks71584 +Node: highline-options72095 +Node: after-save-commands72987 +Node: atomic-extents73811 +Node: array74576 +Node: floating-toolbar74912 +Node: The Toolbar Utilities76052 +Node: Adding Buttons on the Fly77543 +Node: The Toolbar Editor80993 +Node: APIs for Adding and Killing83370 +Node: APIs for Search88574 +Node: Toolbar Portability91336 +Node: foldout92193 +Node: func-menu96049 +Node: id-select97275 +Node: outl-mouse100707 +Node: page-ext101705 +Node: page-ext-keys102493 +Node: page-ext-using103624 +Node: page-ext-addr104792 +Node: power-macros110461 +Node: redo111591 +Node: scroll-in-place112768 +Node: sip-features113119 +Node: sip-commands121725 +Node: sip-install124242 +Node: sip-customize125071 +Node: setnu126816 +Node: vertical-mode127295 +Node: align127778 +Node: Align Usage128270 +Node: allout129299 +Node: narrow-stack132503 +Node: flow-ctrl133047 +Node: makesum133865 +Node: man134179 +Node: abbrevlist134606 +Node: file-part134783 +Node: info-look135024 +Node: live-icon135266 +Node: mode-motion+135515 +Node: popper135759 +Node: reportmail135972 +Node: balloon-help136189 +Node: blink-paren136393 +Node: edit-faces136587 +Node: lispm-fonts136762 +Node: big-menubar136937 +Node: tree-menu137111 +Node: XEmacs License137284 + +End Tag Table diff --git a/xemacs-packages/info/os-utils.info b/xemacs-packages/info/os-utils.info new file mode 100644 index 00000000..45d3653b --- /dev/null +++ b/xemacs-packages/info/os-utils.info @@ -0,0 +1,849 @@ +This is os-utils.info, produced by makeinfo version 4.7 from +os-utils.texi. + +INFO-DIR-SECTION XEmacs Editor +START-INFO-DIR-ENTRY +* OS Utilities: (os-utils). Operating System Utilities for XEmacs. +END-INFO-DIR-ENTRY + + This manual is part of XEmacs. + + XEmacs 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. + + XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + + +File: os-utils.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) + +1 The Operating System Utilities Package +**************************************** + +This Info file contains the manual for the Operating System Utilities +package. + +The node name for each entry in the menu is the name of the elisp file +containing the code that implements the functionality described. It is +highly recommended that you briefly peruse the elisp source code since +it can provide valuable information on usage and technique. This can +easily be done by typing `C-x 4 l RET' where is +the name of the elisp file to be loaded. + +* Menu: + +* Copying:: Why this manual is GPL, and what that means + +Archive Management +* tar-mode:: Simple Editing of TAR Files +* arc-mode:: Simple Editing of Archives + +Compression/Decompression +* crypt:: Handling for Compressed and Encrypted Files +* jka-compr:: Reading/Writing/Loading Compressed Files +* uncompress:: Auto-Decompression Hook for Visiting .Z Files + +Communications +* telnet:: Execute a Telnet Session From Within an Emacs Buffer +* ssh:: Remote Login Interface Using SSH +* ftelnet:: Remote Login Interface Using Telnet +* rlogin:: Remote Login Interface Using rlogin +* mchat:: Multicast Chatting +* kermit:: Using Shell Mode With Kermit +* terminal:: Terminal Emulator + +Miscellaneous +* spell:: Spelling Correction +* background:: Fun With Background Jobs +* inf-lisp:: Inferior-Lisp Mode +* ledit:: ledit + +Appendices: +* XEmacs License:: The GNU General Public License + + +File: os-utils.info, Node: Copying, Next: tar-mode, Prev: Top, Up: Top + +2 Copying +********* + +This document may be redistributed, verbatim or in modified form, under +the terms of the GNU General Public License, version 2 or any later +version. The same terms apply to the libraries it documents. A copy +of the General Public License is provided as an Appendix. + + Most XEmacs documentation has its own license, which is an ancestor +of the GNU Free Documentation License ("FDL"), and whose terms are +quite similar to those imposed by GNU on Emacs documentation. Why is +this manual licensed differently (under the GNU General Public License, +or "GPL"), and why does it have to be distributed separately from the +XEmacs User's Guide and the XEmacs Lisp Reference Manual? + + Taking the second question first, XEmacs is "community-owned" +software. That is, unlike GNU Emacs, there is no monopoly copyright +holder. Many of us, including the original Lucid authors, have +contributed our copyrights to the Free Software Foundation (FSF), and of +course much content is derived from GNU Emacs, and therefore is held by +the FSF. Another large chunk is held by Sun Microsystems, and a few +individual authors hold copyright to thousands of lines each. But many +individuals hold copyright to only a few dozen lines. Like the Linux +kernel, copyright ownership is distributed throughout a community. + + However, its license is "copyleft," _i.e._, it _requires_ that you +redistribute it under terms _identical_ to those under which you +received it, unless you have explicit permission of the copyright +holder. Because of the multiple owners, determining the ownership of +any given part of XEmacs is tedious, and perhaps impossible. For +practical purposes, then, the license of any substantial chunk of +existing XEmacs content cannot be changed, except to a later version of +the GPL, for those parts under GPL. (That is due to the _explicit_ +permission to change to a later version of the GPL, present in every +file of XEmacs.) + + Unfortunately, this severe restriction means that the GPL, FDL, and +the XEmacs documentation license ("XDL") are _mutually incompatible_. +That is, content licensed under any of the GPL, FDL, or XDL _may not_ +be mixed with content licensed under either of the other two without +changing the license of some of the content. But this requires +permission of the copyright holder, which is often difficult or +impossible to get. + + For example, you _may not_ take comments or docstrings from XEmacs +code and add them to the Lispref to mend a gap in the latter's coverage. +You _may not_ copy text from the Lispref into docstrings in the code. +And you _may not_ copy text from the GNU Emacs Lisp Reference to the +XEmacs Lisp Reference Manual. (In this case it is at least trivial to +ask permission, although it is rather unclear whether it would be +granted.) + + In fact, parts of this document were derived by copying from XEmacs +code under the GPL, without any further permission from the authors. +Thus, this document must be distributed under the GPL, as a "volume" +separate from the XEmacs documentation under the XDL. Note that the +"mere aggregation" clauses allow us to distribute in the same tarball. +But incorporating it as a node in the Lispref is prohibited, even if +done by inclusion. + + A bit of advocacy: + + If you look carefully at the additional restrictions imposed by the +soi-disant "free" documentation licenses, you discover that they are +simply proprietary restrictions guaranteeing a certain amount of +_unpaid_ political advertising to the Free Software Foundation and GNU +Project (and in the case of the FDL, this is extended to commercial +advertising by authors of original or derived works). Whether this is +"ethically justified" or not is a difficult question. What is certain +is that there is little social benefit to these terms (since the license +documents themselves contain the advocacy and must be included with any +distribution). + + I conclude it makes sense for XEmacs to reduce its restrictions, +where possible, to the "least common denominator," the GNU General +Public License. + + +File: os-utils.info, Node: tar-mode, Next: arc-mode, Prev: Copying, Up: Top + +3 Simple Editing of TAR Files +***************************** + +This package attempts to make dealing with Unix 'tar' archives easier. +When this code is loaded, visiting a file whose name ends in '.tar' +will cause the contents of that archive file to be displayed in a +Dired-like listing. It is then possible to use the customary Dired +keybindings to extract sub-files from that archive, either by reading +them into their own editor buffers, or by copying them directly to +arbitrary files on disk. It is also possible to delete sub-files from +within the tar file and write the modified archive back to disk, or to +edit sub-files within the archive and re-insert the modified files into +the archive. See the documentation string of `tar-mode' for more info. + + To configure this package, type: + + M-x customize-group RET tar RET + + +File: os-utils.info, Node: arc-mode, Next: crypt, Prev: tar-mode, Up: Top + +4 Simple Editing of Archives +**************************** + +This library not documented. Please contribute! + + To configure this package, type: + + M-x customize-group RET archive RET + + +File: os-utils.info, Node: crypt, Next: jka-compr, Prev: arc-mode, Up: Top + +5 Handling for Compressed and Encrypted Files +********************************************* + +The basic purpose of this package of Lisp functions is to recognize +automatically encrypted and encoded (i.e., compressed) files when they +are first visited or written. The BUFFER corresponding to the file is +decoded and/or decrypted before it is presented to the user. The file +itself is unchanged on the disk. When the buffer is subsequently saved +to disk, a hook function re-encodes the buffer before the actual disk +write takes place. + + This package recognizes all sorts of compressed files by a magic +number at the beginning of these files but uses a heuristic to detect +encrypted files. If you are asked for an encryption key for a file +that is in fact not encrypted, just hit RET and the file will be +accepted as is, and the crypt minor mode will not be entered. + + Other types of encoding programs may be added to this package by +using the variable `crypt-encoding-alist' which contains a table of +encoding programs such as `compress', `gzip' (GNU zip), `freeze', and +`compact'. + + This new extended version of crypt now monitors the filename +extensions of buffers that are written out using `write-file' (`C-x +C-w'). If the filename extension matches one of the extensions listed +in `crypt-encoding-alist', then this package will write the file out +using the corresponding encoding (compression) method. This is done +whether or not the buffer originated from a previously encoded +(compressed) file. + + Thus, if the user is editing a file that may or may not have been +encoded originally (e.g., `foobar.Z' or `foobar') and decides to write +it to a different file (e.g., `barfoo' or `barfoo.z' or `barfoo.C'). +This package will examine the filename extension and write the buffer +in plain format or an alternate encoding (compression) format by +searching through the entries in the table of encoding methods +`crypt-encoding-alist'. This change in encoding state is done +automatically if the variable `crypt-auto-write-buffer' is t otherwise +the user is asked. + + To use this package, put the line `(require 'crypt)' in your +initialization file. Do not bother trying to autoload this file; this +package uses `find-file' and `write-file' hooks and thus should be +loaded the first time you visit any sort of file. Any package loaded +after this one that appends something to `write-file-hooks' will not be +executed because this package writes out the file. Other packages that +append to `write-file-hooks' should either be modified to prepend to +that hook or be loaded before this one (preferably the former). + + NOTE: encryption users should set `crypt-encryption-type' to one of +the values in `crypt-encryption-alist'. + + To configure this package, type: + + M-x customize-group RET compression RET + + +File: os-utils.info, Node: jka-compr, Next: uncompress, Prev: crypt, Up: Top + +6 Reading/Writing/Loading Compressed Files +****************************************** + +This package implements low-level support for reading, writing, and +loading compressed files. It hooks into the low-level file I/O +functions (including `write-region' and `insert-file-contents') so that +they automatically compress or uncompress a file if the file appears to +need it (based on the extension of the file name). Packages like +Rmail, VM, GNUS, and Info should be able to work with compressed files +without modification. + + The operation of this package should be transparent to the user +(except for messages appearing when a file is being compressed or +uncompressed). + + The variable, `jka-compr-compression-info-list' can be used to +customize `jka-compr' to work with other compression programs. The +default value of this variable allows `jka-compr' to work with Unix +compress and gzip. + + To activate this package, add the following to your initialization +file: + + (toggle-auto-compression 1 t) ; enable compression/decompression + + To configure this package, type: + + M-x customize-group RET jka-compr RET + + +File: os-utils.info, Node: uncompress, Next: telnet, Prev: jka-compr, Up: Top + +7 Auto-Decompression Hook for Visiting .Z Files +*********************************************** + +This package can be used to arrange for automatic uncompress of +compressed files when they are visited. All that's necessary is to +load it. This can conveniently be done from your initialization file. + + `M-x auto-compression-mode' is a more modern replacement for this +package. + + +File: os-utils.info, Node: telnet, Next: ssh, Prev: uncompress, Up: Top + +8 Execute a Telnet Session From Within an Emacs Buffer +****************************************************** + +This mode is intended to be used for telnet or rsh to a remote host; +`telnet' and `rsh' are the two entry points. Multiple telnet or rsh +sessions are supported. + + Normally, input is sent to the remote telnet/rsh line-by-line, as +you type `RET' or `LFD'. `C-c C-c' sends a `C-c' to the remote +immediately; `C-c C-z' sends `C-z' immediately. `C-c C-q' followed by +any character sends that character immediately. + + All `RET' characters are filtered out of the output coming back from +the remote system. The mode tries to do other useful translations +based on what it sees coming back from the other system before the +password query. It knows about UNIX, ITS, TOPS-20 and Explorer systems. + + You can use the global `telnet-host-properties' to associate a telnet +program and login name with each host you regularly telnet to. + + To configure this package, type: + + M-x customize-group RET telnet RET + + +File: os-utils.info, Node: ssh, Next: ftelnet, Prev: telnet, Up: Top + +9 Remote Login Interface Using SSH +********************************** + +This package provides support for remote logins using `ssh'. The +package is layered on top of shell.el; the code here only accounts for +the variations needed to handle a remote process, e.g. directory +tracking and the sending of some special characters. + + If you wish for ssh mode to prompt you in the minibuffer for +passwords when a password prompt appears, just enter `M-x +send-invisible' and type in your line, or add +`comint-watch-for-password-prompt' to `comint-output-filter-functions'. + + To configure this package, type: + + M-x customize-group RET ssh RET + + +File: os-utils.info, Node: ftelnet, Next: rlogin, Prev: ssh, Up: Top + +10 Remote Login Interface Using Telnet +************************************** + +This package provides support for remote logins using `telnet'. The +package is layered on top of shell.el; the code here only accounts for +the variations needed to handle a remote process, e.g. directory +tracking and the sending of some special characters. + + If you wish for ftelnet mode to prompt you in the minibuffer for +passwords when a password prompt appears, just enter `M-x +send-invisible' and type in your line, or add +`comint-watch-for-password-prompt' to `comint-output-filter-functions'. + + +File: os-utils.info, Node: rlogin, Next: mchat, Prev: ftelnet, Up: Top + +11 Remote Login Interface Using rlogin +************************************** + +This package provides support for remote logins using `rlogin'. The +package is layered on top of shell.el; the code here only accounts for +the variations needed to handle a remote process, e.g. directory +tracking and the sending of some special characters. + + If you wish for rlogin mode to prompt you in the minibuffer for +passwords when a password prompt appears, just enter `M-x +send-invisible' and type in your line, or add +`comint-watch-for-password-prompt' to `comint-output-filter-functions'. + + To configure this package, type: + + M-x customize-group RET rlogin RET + + +File: os-utils.info, Node: mchat, Next: kermit, Prev: rlogin, Up: Top + +12 Multicast Chatting +********************* + +MChat is a package allowing a conversation to take place between a +potentially infinite number of people across the Internet. It uses the +Multicast support that has been added to XEmacs in the early 21.0 days. +At that time a rudimentary version of MChat was written, merely to +illustrate the feature, and almost nobody knew it, apart from the other +developers. This version is much improved and completely backwards +incompatible ;-). + + NOTE: before using this package, you most likely have to customize +the `mchat-nsl-method' first. It specifies a program like `nsl' or +`nslookup' in order to retrieve the IP number of your machine. + + The main entry point to the package is the `mchat' function which +allows you to open a multicast group based on the MChat protocol. There +are a number a variables that can be customized and their doc-string +should be self-explanatory. You might also want to look at the bindings +(`C-h b') in MChat buffers, or at the menubar entries to get an idea of +what you can do. + + WARNING: the current version (but there's also a limitation in the +internals of XEmacs's processes) doesn't let you send messages longer +than 500 octets or so, including the protocol header. I plan to change +this in the future (see the todo list). + + To configure this package, type: + + M-x customize-group RET mchat RET + + +File: os-utils.info, Node: kermit, Next: terminal, Prev: mchat, Up: Top + +13 Using Shell Mode With Kermit +******************************* + +This library not documented. Please contribute! + + +File: os-utils.info, Node: terminal, Next: spell, Prev: kermit, Up: Top + +14 Terminal Emulator +******************** + +This library not documented. Please contribute! + + +File: os-utils.info, Node: spell, Next: background, Prev: terminal, Up: Top + +15 Spelling Correction +********************** + +This mode provides an Emacs interface to the UNIX spell(1) program. +Entry points are `spell-buffer', `spell-word', `spell-region' and +`spell-string'. These facilities are documented in the Emacs user's +manual. + + +File: os-utils.info, Node: background, Next: inf-lisp, Prev: spell, Up: Top + +16 Fun With Background Jobs +*************************** + +This library not documented. Please contribute! + + To configure this package, type: + + M-x customize-group RET background RET + + +File: os-utils.info, Node: inf-lisp, Next: ledit, Prev: background, Up: Top + +17 Inferior-Lisp Mode +********************* + +This library not documented. Please contribute! + + +File: os-utils.info, Node: ledit, Next: XEmacs License, Prev: inf-lisp, Up: Top + +18 ledit +******** + +This library not documented. Please contribute! + + +File: os-utils.info, Node: XEmacs License, Prev: ledit, Up: Top + +19 XEmacs License +***************** + +GNU GENERAL PUBLIC LICENSE +************************** + + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble +======== + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", + below, refers to any such program or work, and a "work based on + the Program" means either the Program or any derivative work under + copyright law: that is to say, a work containing the Program or a + portion of it, either verbatim or with modifications and/or + translated into another language. (Hereinafter, translation is + included without limitation in the term "modification".) Each + licensee is addressed as "you". + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running the Program is not restricted, and the output from the + Program is covered only if its contents constitute a work based on + the Program (independent of having been made by running the + Program). Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any + warranty; and give any other recipients of the Program a copy of + this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b. You must cause any work that you distribute or publish, that + in whole or in part contains or is derived from the Program + or any part thereof, to be licensed as a whole at no charge + to all third parties under the terms of this License. + + c. If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display + an announcement including an appropriate copyright notice and + a notice that there is no warranty (or else, saying that you + provide a warranty) and that users may redistribute the + program under these conditions, and telling the user how to + view a copy of this License. (Exception: if the Program + itself is interactive but does not normally print such an + announcement, your work based on the Program is not required + to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Program, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Program, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Program. + + In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you also do one of the + following: + + a. Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Sections 1 and 2 above on a medium customarily used for + software interchange; or, + + b. Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or, + + c. Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with + such an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete + source code means all the source code for all modules it contains, + plus any associated interface definition files, plus the scripts + used to control compilation and installation of the executable. + However, as a special exception, the source code distributed need + not include anything that is normally distributed (in either + source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable + runs, unless that component itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Program or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Program (or any work + based on the Program), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program + subject to these terms and conditions. You may not impose any + further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Program at all. For example, if a patent license would not permit + royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Program under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 9. The Free Software Foundation may publish revised and/or new + versions of the General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Program + does not specify a version number of this License, you may choose + any version ever published by the Free Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the + author to ask for permission. For software which is copyrighted + by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision + will be guided by the two goals of preserving the free status of + all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY + OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) 19YY NAME OF AUTHOR + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Also add information on how to contact you by electronic and paper +mail. + + If the program is interactive, make it output a short notice like +this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + + The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + SIGNATURE OF TY COON, 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Library General Public License instead of this License. + + + +Tag Table: +Node: Top928 +Node: Copying2796 +Node: tar-mode6943 +Node: arc-mode7861 +Node: crypt8132 +Node: jka-compr11033 +Node: uncompress12245 +Node: telnet12710 +Node: ssh13813 +Node: ftelnet14534 +Node: rlogin15193 +Node: mchat15933 +Node: kermit17394 +Node: terminal17588 +Node: spell17760 +Node: background18102 +Node: inf-lisp18376 +Node: ledit18554 +Node: XEmacs License18710 + +End Tag Table diff --git a/xemacs-packages/info/patcher.info b/xemacs-packages/info/patcher.info new file mode 100644 index 00000000..65ec78c5 --- /dev/null +++ b/xemacs-packages/info/patcher.info @@ -0,0 +1,1887 @@ +This is patcher.info, produced by makeinfo version 4.6 from +patcher.texi. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Patcher: (patcher). Automatic archive-based projects maintenance. +END-INFO-DIR-ENTRY + + This file contains the documentation for Patcher version 3.8, an +XEmacs package for automating the maintenance of archive-based projects. + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Didier Verna. + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the sections entitled "Copying" and "GNU General Public License" +are included exactly as in the original, and provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Free Software Foundation. + + +File: patcher.info, Node: Top, Next: Copying, Up: (dir) + +Patcher +******* + +Patcher is an XEmacs package designed to automate and ease the +maintenance of archive-based projects. It provides assistance in +building, reporting and committing patches, as well as in handling the +corresponding ChangeLog entries, for example by creating skeletons. + + This info file documents Patcher version 3.8. + +* Menu: + +* Copying:: The GNU General Public License +* Introduction:: What Patcher is all about +* Installation:: How to get and install Patcher +* Quick Start:: For the brave and the impatient +* User Manual:: A step-by-step guide to using Patcher +* Variables Index:: +* Functions Index:: +* Keystrokes Index:: + + Patcher is developed by Didier Verna . + + +File: patcher.info, Node: Copying, Next: Introduction, Prev: Top, Up: Top + +Copying +******* + +Patcher is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License version 2, as published by +the Software Foundation. + + Patcher 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 this program; if not, write to the Free Software Foundation, +Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +File: patcher.info, Node: Introduction, Next: Installation, Prev: Copying, Up: Top + +Introduction +************ + +When a project becomes important in size, or when the development is +performed cooperatively by several people across the Internet, it is a +common practice to help maintaining it by using a development control +system. Such tools (CVS, PRCS, to name a few) usually work by +maintaining a centralized project archive (also called a repository) +that keeps track of the history of the changes, lets you develop +different "branches" at the same time and perform operations like +merges between these different project branches. + + In such "archive-based" maintenance models, making the project evolve +usually involves repeatedly the same few steps, some of which can be +tedious: you work on your local copy of the project; once you're +satisfied with your changes, you create a patch by diffing your local +copy against the project's archive; then (or progressively), you +construct the ChangeLog entries. Finally, you propose your changes by +sending a mail to the developers list with your patch and the ChangeLog +entries included, hoping that your proposition will be accepted. If +you're one of the maintainers, you will still probably send the message +to the list, simply announcing the modification, and immediately commit +the patch with an informative log message. + + Patcher is an XEmacs package designed to automate this process. +Patcher can't work on the project for you. However, as soon as you give +it some basic knowledge on the project structure and repository, it can +automatically build a patch by comparing your local copy with the +repository, create ChangeLog entries, prepare a mail announcing the +changes, and even commit the patch for you with a informative log +message. All of this is done in just a few keystrokes. Additionally, +Patcher can perform some sanity checks, like verifying that your local +copy is up-to-date, that you did not forget some ChangeLog entries, that +the commit operation went well and so on. + + If you're brave and impatient, and want to start using the basics of +Patcher as soon as possible, see *Note Quick Start::. It is recommended +to read it anyway, since it gives an overview of how Patcher works. If +you know the basics and want a more detailed guide, see *Note User +Manual::. + + Enjoy using Patcher ! + + +File: patcher.info, Node: Installation, Next: Quick Start, Prev: Introduction, Up: Top + +Installation +************ + +* Menu: + +* Distribution:: How to get Patcher +* Requirements:: What you need to get Patcher running +* Insinuation:: How to plug Patcher into other libraries + + +File: patcher.info, Node: Distribution, Next: Requirements, Up: Installation + +Distribution +============ + +Patcher is available either as a standalone package, or as part of the +standard `xemacs-devel' XEmacs package. + + You can get `xemacs-devel' in three different ways: + * You can install `xemacs-devel' from within XEmacs via the package + user interface (accessible from the `Tools' menu or via `M-x + list-packages'). + + * You can also download the `xemacs-devel--pkg.tar.gz' + tarball from `ftp://ftp.xemacs.org/pub/xemacs/packages/', and + unpack it where you put the other packages. + + * `xemacs-devel' sources are available from the XEmacs CVS + repository. The module name is `xemacs-devel'. See + `http://www.xemacs.org/Develop/cvsaccess.html' for more information + about the XEmacs CVS repository. + + I also provide Patcher as a standalone package. This is mainly for my +personal usage (when developing and debugging new versions) but you +might want to use it if you're not interested in the rest of +`xemacs-devel'. The standalone version of Patcher can be found at +`http://www.lrde.epita.fr/~didier/comp/development/software.php'. You +will also find different inlined versions of this documentation at that +place. For installation instructions, please read the `INSTALL' file. + + +File: patcher.info, Node: Requirements, Next: Insinuation, Prev: Distribution, Up: Installation + +Requirements +============ + +Patcher currently works only with XEmacs 21.4 or later. I'm not sure it +works with earlier versions of XEmacs, but I'm sure it does *not* work +with GNU Emacs (see below). + + Patcher might also have some other requirements, depending on how +you use it: + + * If you let Patcher create ChangeLogs for you (*note ChangeLogs + Handling::), you will need the `add-log' library from the + `xemacs-base' package, version 1.48 or later, installed on your + system. That's actually the may reason for Patcher not being able + to run in GNU Emacs, though I have not tried to port it yet. + + * If you want to send mails from Patcher (*note Mail Methods::), you + will need a mail user agent. Patcher currently supports `sendmail', + `message' and `Gnus' natively and through the `compose-mail' + interface. Other MUA might be partly supported when used with + `compose-mail'. Patcher will probably suffer from non critical + deficiencies in that case however (it will issue warnings). + + +File: patcher.info, Node: Insinuation, Prev: Requirements, Up: Installation + +Insinuation +=========== + +With a proper installation of Patcher (either way), you don't need any +special trickery in your `.emacs' file because all entry points to the +library should be autoloaded. + + However, Patcher has the ability to hook into external libraries, but +won't do so unless requested. Currently, Patcher has hooks for Gnus +only. If you're using Gnus as your MUA, you might want to add the +following line to your `gnusrc' file: + + (patcher-insinuate-gnus) + + This will add some facilities described along the text. + + +File: patcher.info, Node: Quick Start, Next: User Manual, Prev: Installation, Up: Top + +Quick Start +*********** + +In this chapter, we quickly setup the basic Patcher configuration for +hacking on XEmacs. Adapt the example as you wish. Let's make some +assumptions first: + + * You own a computer. + + * You have the `add-log' library from the `xemacs-base' package, + version 1.48 or later, installed on your system. + + * You're using XEmacs from the CVS repository. + + * Your local copy of the repository is located in + `/usr/local/src/XEmacs-21.5'. + + * Your local copy of the repository is up-to-date, but you've done + some hacking in the sources that you'd like to submit. + + * Since you're lazy, you didn't write the ChangeLog entries yet. + +* Menu: + +* Setting up Patcher:: Making Patcher aware of your project +* Calling Patcher:: Preparing a patch and a message +* Filling the ChangeLogs:: Patcher only creates skeletons +* Filling the Message:: You should insert the ChangeLog entries +* Committing the Patch:: Applying your modifications to the archive +* Sending the Message:: Telling people about your modifications + + +File: patcher.info, Node: Setting up Patcher, Next: Calling Patcher, Prev: Quick Start, Up: Quick Start + +Setting up Patcher +================== + +The first thing to do is to make patcher aware of your "XEmacs" +project. Put this in your `.emacs' file: + + (setq patcher-projects + '(("XEmacs" "/usr/local/src/XEmacs-21.5" + :to-address "xemacs-patches@xemacs.org") + )) + + As you can imagine, `patcher-projects' is a user option in which you +store information about the projects you want to manage with Patcher. +It is actually a list of what's called "project descriptors". Here's +the meaning of the only project descriptor we have in the example +above: we have a project named "XEmacs", located in +`/usr/local/src/XEmacs-21.5' and for which emails should be sent to +. + + Note the particular syntax for specifying the mailing address. This +is what's called a "project option". Contrary to the project's name and +directory, which are mandatory and always appear as the first and second +elements of a project descriptor, project options are optional and can +appear in any order. + + +File: patcher.info, Node: Calling Patcher, Next: Filling the ChangeLogs, Prev: Setting up Patcher, Up: Quick Start + +Calling Patcher +=============== + +Now you want to build a patch with your changes, and prepare a message +to submit them. The way Patcher works is currently to setup the message +first, and then to control all subsequent operations from there. In +other words, to create a patch, you actually ask Patcher to prepare a +mail. Type this: + + M-x patcher-mail + + First, you're prompted (with completion) for a project name (the +first element of each project descriptor, remember ?). We currently +only have an "XEmacs" project, so hitting `TAB' will directly fill the +minibuffer in with this only choice. Then, you're prompted for a subject +line that will be used in the mail. Say something sensible. + + Three operations are now executed in turn: + + 1. Patcher prepares a mail buffer. The message will be sent to the + address you specified with the `:to-address' project option, and + the subject line now reads "[PATCH] something sensible". + + 2. Patcher now builds the patch. The command used to do this is `cvs + -q diff -u' (this is also a project option). Upon successful + completion of this command (we assume that's indeed the case), the + patch is inserted into the mail buffer. Some information about the + patch is provided just above it (the command used, the files + affected and so on). + + 3. Finally, Patcher generates ChangeLog skeletons from what it + understands of the patch. This involves visiting the appropriate + ChangeLog files, and creating initial entries. + + +File: patcher.info, Node: Filling the ChangeLogs, Next: Filling the Message, Prev: Calling Patcher, Up: Quick Start + +Filling the ChangeLogs +====================== + +Patcher has just created initial ChangeLog entries for you. You must now +browse through the ChangeLog file(s) and fill the entries as you see +fit. Once you're done, you can very well save the ChangeLog buffers. +However, don't kill them ! Don't even think about it. Patcher still +needs them. Now, please return to the mail buffer. + + +File: patcher.info, Node: Filling the Message, Next: Committing the Patch, Prev: Filling the ChangeLogs, Up: Quick Start + +Filling the message +=================== + +Now that you're satisfied with your ChangeLog entries and you've +returned to the mail buffer, you want to write some explanation text in +the message. I'll let you do that. You also want to insert the ChangeLog +entries corresponding to your patch, since they are usually much more +readable than the patch itself. + + Inserting your ChangeLog entries in the mail buffer is as simple as +typing `C-c C-p i'. This actually calls the function +`patcher-insert-change-logs', which places them just above the patch, +with a short information line (per ChangeLog file) on top. + + +File: patcher.info, Node: Committing the Patch, Next: Sending the Message, Prev: Filling the Message, Up: Quick Start + +Committing the Patch +==================== + +If you have commit access to your project, you should read this. +Otherwise, you may directly see *Note Sending the Message::. + + Committing your changes involves three steps: preparing the commit +command, preparing the commit log message, and actually committing the +changes. Although Patcher can do all of this in one shot, it lets you +control each step by default. + + In order to start the commit process, simply type `C-c C-p c'. This +calls the function `patcher-commit-change'. Congratulations. You've +just been transported to a new buffer, the `*Patcher Log Message*' +buffer. This buffer lets you edit the log message that will accompany +your commit. Note that the message is initialized with the subject line +of your mail. This is also a project option. + + Once you're satisfied with the log message, type `C-c C-c'. This +calls the function `patcher-logmsg-commit', which computes the commit +command to use. The command is displayed in a special buffer, the +`*Patcher Commit Command*' buffer. The default commit command is `cvs +commit', which of course is also a project option. Note that Patcher +stores the log message in a temporary file and uses the `-F' `cvs +commit' option. Finally, note that Patcher has automatically appended +the affected ChangeLog files to the commit command. + + At this point, you have the opportunity to abort the commit +operation. Otherwise, answer positively and the commit will be +executed. If you had not previously saved the ChangeLog files, Patcher +will do it for you just before committing. + + +File: patcher.info, Node: Sending the Message, Prev: Committing the Patch, Up: Quick Start + +Sending the Message +=================== + +Sending the message has actually nothing to do with Patcher. It depends +on the method you use for sending mails, but will usually be done via a +`C-c C-c' command of some sort. On thing to note however: if you've +committed your changes via Patcher, the message has been slightly +modified: the subject line now reads "[COMMIT] something sensible" +instead of "[PATCH] ...", and a short commit notice has been inserted +just at the beginning of the message's body. + + That's it. That was easy. Congratulations on your first shot at +Patcher, anyway ! Of course, Patcher is much more powerful and +customizable than what has been described in this chapter. For a +complete documentation on how to use and customize Patcher, please +refer to *Note User Manual::. + + +File: patcher.info, Node: User Manual, Next: Variables Index, Prev: Quick Start, Up: Top + +User Manual +*********** + +This chapter provides a step-by-step guide to using Patcher. Everything +there is to know about Patcher is here, though the features are +introduced progressively. + + All user options that are going to be presented in this manual can be +found in the `patcher' customization group, or a subgroup of it. + +* Menu: + +* Project Descriptors:: The project specification mechanism +* Mail Preparation:: Customizing Patcher messages +* Patch Generation:: Specifying how a patch is to be constructed +* ChangeLogs Handling:: How Patcher behaves with respect to ChangeLogs +* Project Check In:: Committing your changes from Patcher +* Mail Sending:: Sending the message and cleaning up the place +* More On Commands:: Error handling and other generalities +* More On Subprojects:: Defining permanent subprojects + + +File: patcher.info, Node: Project Descriptors, Next: Mail Preparation, Prev: User Manual, Up: User Manual + +Project Descriptors +=================== + +Projects specifications are stored in `patcher-projects'. This user +option is actually a list of "project descriptors". Each project +descriptor has the following form: `(NAME DIR :OPTION VALUE ...)' + + NAME is a string naming your project, DIR is a string specifying the +directory in which it resides. The remainder of a project descriptor is +a sequence of zero or more option/value pairs, that we call "project +options". All option names start with a colon. The type of a value +depends on the corresponding option. For example, there is a project +option named `:to-address', whose value should be a string giving the +email address to which you want to send Patcher messages. + + When Patcher needs the value for a particular project option, it +looks for it directly in the project descriptor, but also in other +places. This process is described below. + +* Menu: + +* Themes:: Collections of options +* Project inheritance:: Getting options from other projects +* Fallbacks:: Default values for project options +* Retrieval:: The process of getting an option's value +* Inheritance or theme ?:: The proper way to factor out option values + + +File: patcher.info, Node: Themes, Next: Project inheritance, Up: Project Descriptors + +Themes +------ + +If you have several projects sharing the same option set, you might want +to setup a theme. Themes are named collections of project options. + + Themes are stored in the `patcher-themes' user option. This option +is a list of themes. Each theme has the following form: `(NAME :OPTION +VALUE ...)'. + + NAME is the theme's name (a symbol). The remainder of the list is a +sequence of zero or more option/value pairs, just like in project +descriptors. + + In order to use a theme in a given project, a `:themes' project +option is provided. It is a list of theme names (symbols). Use this +option in your project descriptor, and the project will implicitly +inherit all options from the corresponding theme. + + One important note: as `:themes' is a project option, it can appear +in a theme. In other words, themes can inherit from other themes. When +Patcher tries to retrieve an option, the themes tree is traversed in +depth first. + + Because themes can contain themes, a bogus setting might lead to an +infinite loop (a cycle in a theme graph). To prevent this, the +`patcher-max-theme-depth' user option is provided. It represents the +expected maximum theme nesting level, and defaults to 8. + + +File: patcher.info, Node: Project inheritance, Next: Fallbacks, Prev: Themes, Up: Project Descriptors + +Project inheritance +------------------- + +When two projects are very similar, you might want to use the project +inheritance mechanism described below. + + There is a special project option called `:inheritance'. This option +must be a list of project names (strings). The inheritance of a project +defines a list of projects from which to inherit options. + + One important note: inherited projects might have their own +`:inheritance' option set to other projects in turn. In other words, +the project inheritance can be more than one level deep. When Patcher +tries to retrieve an option, the inheritance tree is traversed in depth +first. + + Because inherited projects can inherit from projects, a bogus setting +might lead to an infinite loop (a cycle in a project graph). To prevent +this, the `patcher-max-inheritance-depth' user option is provided. It +represents the expected maximum project inheritance level, and defaults +to 8. + + The `:inheritance' project option is somewhat special in the sense +that it can't appear in a theme. We will encounter other exceptions +later in this manual. + + +File: patcher.info, Node: Fallbacks, Next: Retrieval, Prev: Project inheritance, Up: Project Descriptors + +Fallbacks +--------- + +For each existing project option, Patcher also has a "fallback" user +option with a default value that would be shared among all (or some of) +your projects. The name of the fallback is obtained by replacing the +colon in the project option's name with the prefix `patcher-default-'. +For example, the fallback corresponding to the `:to-address' project +option is named `patcher-default-to-address'. + + The `:inheritance' project option is also special in the sense that +it doesn't have a corresponding fallback. We will encounter other +exceptions later in this manual. + + In the remainder of this manual, we will rarely mention the fallbacks +again. When we introduce a new project option, just remember that it +always has a corresponding fallback (well, not always, as you just +discovered). + + +File: patcher.info, Node: Retrieval, Next: Inheritance or theme ?, Prev: Fallbacks, Up: Project Descriptors + +Retrieval +--------- + +When Patcher needs the value of a particular project option, it looks +for it in the following manner: + + * First, it looks directly in the project descriptor to see if the + option is given. + + * If that fails, it next tries the given themes, if any. This + involves recursively traversing the project's themes tree. Options + successfully retrieved in themes are said to be "themed". + + * If that still fails, it then tries the inherited projects, if any. + This involves recursively traversing the project's inheritance + tree. Options successfully retrieved in inherited projects are + said to be "inherited". Note that in turn, such options could have + been actually themed in the inherited project. + + * If that fails again, it finally falls back to the value given in + the corresponding fallback (if it exists). In such a case, the + option is said to be "fallbacked". + + Note that a value of `nil' for a project option *is an actual +value*. It is not equivalent to an option being unset. As a +consequence, if Patcher finds a project option with a value of `nil' +somewhere, it will use it and stop the search, even if a non nil value +could be retrieved later from a theme, an inherited project or a +fallback. This provides you with a way to annihilate themed, inherited +or fallbacked options. + + +File: patcher.info, Node: Inheritance or theme ?, Prev: Retrieval, Up: Project Descriptors + +Inheritance or theme ? +---------------------- + +At that point, you might be wondering why the themes and inheritance +concepts were both designed, since they actually perform very similar +tasks. Good question. Here is a good answer. + + Projects might share options for different reasons. For example, my +"XEmacs" (source) and "XEmacs Packages" projects share many options +(`To:' address, `From:' address, diff and commit commands and so on) +because they both relate to XEmacs. On the other hand I have personal +but totally unrelated projects that share the same commands because +they are all handled through a local PRCS archive. + + In other words, you should rather use the inheritance mechanism when +projects relate to each other, and the theme mechanism for settings that +are orthogonal the projects they apply to. + + +File: patcher.info, Node: Mail Preparation, Next: Patch Generation, Prev: Project Descriptors, Up: User Manual + +Mail Preparation +================ + +Patcher currently uses the mail buffers as "master" buffers for +controlling all operations: building a patch, creating the ChangeLog +entries, committing... all is done from the mail buffer. Note however +that you don't need to actually send mails to use Patcher (*note Fake +Mail Method::). + + To use Patcher on a certain project, you start by preparing a +(possibly fake) mail. There are several ways to do so: you could start +a brand new message, "adapt" a message already in preparation to +Patcher, or even compose some sort of a Patcher reply to another +message. + + - Function: patcher-mail + Start composing a brand new Patcher message. This function + interactively prompts you for the name of the project and for a + (mail) subject line. + + - Function: patcher-mail-adapt + Assuming that you are already editing a message (with your usual + MUA), this function "adapts" it to Patcher by prompting you for + the name of a project. Note that this function does _not_ prompt + you for a subject. + + If you're using Gnus to read mail and have properly insinuated it +(*note Insinuation::), Patcher offers different Gnus-like ways to answer +mails and adapt them to Patcher. All the functions below are available +from both the Gnus Summary and the Article buffer. + + - Function: patcher-gnus-summary-followup + Compose a followup to the article, and adapt it to Patcher. This + function is bound to `C-c C-p f'. + + - Function: patcher-gnus-summary-followup-with-original + Idem, but also cite the original article. This function is bound to + `C-c C-p F'. + + - Function: patcher-gnus-summary-reply + Like `patcher-gnus-summary-followup', but compose a reply. This + function is bound to `C-c C-p r'. + + - Function: patcher-gnus-summary-reply-with-original + Idem, but also cite the original article. This function is bound to + `C-c C-p R'. + + In any case, Patcher starts working on the project (by first creating +the patch) after the message is prepared. Because of this, we'll start +by reviewing the mail-related customizations you might want to setup. + +* Menu: + +* Mail Methods:: Using a particular mailer +* Message Customization:: Specifying initial contents for messages + + +File: patcher.info, Node: Mail Methods, Next: Message Customization, Prev: Mail Preparation, Up: Mail Preparation + +Mail Methods +------------ + +Since there are different mail packages working in XEmacs, Patcher +supports different methods for preparing messages. You can specify the +method you prefer in the `:mail-method' project option. The value must +be a symbol. + +* Menu: + +* Standard Mail Methods:: Patcher supports standard mail packages +* Fake Mail Method:: Patcher supports not sending mails +* Other Mail Methods:: Patcher supports everything + + +File: patcher.info, Node: Standard Mail Methods, Next: Fake Mail Method, Prev: Mail Methods, Up: Mail Methods + +Standard Mail Methods +..................... + +Patcher currently supports `sendmail', `message' and `Gnus' natively +and through the `compose-mail' interface. Other MUA might be partly +supported when used with `compose-mail'. Patcher will probably suffer +from non critical deficiencies in that case however (it will issue +warnings). + +`compose-mail' + This is the default. It is implemented via the function + `patcher-mail-compose-mail' which calls `compose-mail' to prepare + the message. If you are not familiar with `compose-mail', you + might also want to throw an eye to the user option + `mail-user-agent'. If your project does not specify an address to + send the message to (*note Message Customization::), it is + prompted for. + +`sendmail' + A direct interface to the `mail' function from the `sendmail' + package. It is implemented via the function + `patcher-mail-sendmail'. If your project does not specify an + address to send the message to (*note Message Customization::), it + is prompted for. + +`message' + A direct interface to the `message-mail' function from the + `message' library (it is part of `Gnus'). It is implemented via + the function `patcher-mail-message'. If your project does not + specify an address to send the message to (*note Message + Customization::), it is prompted for. + +`gnus' + A direct interface to the `gnus-post-news' function from the + `Gnus' package (it can also send mails...). It is implemented via + the function `patcher-mail-gnus'. This mail method is interesting + when you maintain a special mail group for messages that you send + with Patcher, most probably because they are sent to some + mailing-list, such as . + + This method uses a Gnus group name and acts as if you had type `C-u + a' on that group in the `*Group*' buffer, hence honoring the group + parameters and posting-styles. If your project does not specify a + Gnus group name (*note Message Customization::), it is prompted + for. + + This last mail method is special in the sense that it requires a +running Gnus session to work. If that's needed, Patcher can start Gnus +for you in several ways, according to the following user options: + +`patcher-mail-run-gnus' + If `nil', Patcher will never start Gnus and abort the operation + instead. If `t', Patcher will always start Gnus when needed. If + `'prompt', Patcher will ask you what (you want) to do. This is the + default behavior. + +`patcher-mail-run-gnus-other-frame' + Used when Patcher has to start Gnus by itself. If `nil', continue + using the current frame. If `t', start Gnus in another frame (this + is the default). If `'follow', start Gnus in another frame, and use + this new frame to prepare the Patcher mail. + + +File: patcher.info, Node: Fake Mail Method, Next: Other Mail Methods, Prev: Standard Mail Methods, Up: Mail Methods + +Fake Mail Method +................ + +At that point, you might be wondering why the mail method is a project +option and not simply a user option, since you probably only use one +mail agent at all. Right. But you might one day work on projects for +which you don't need to send messages at all. This could happen if you +start using Patcher on a project of your own for instance. For that +reason, there is a `fake' mail method available. It is implemented via +the `patcher-mail-fake' function and calls no particular mail user +agent. Once you type `C-c C-c' to virtually send the fake message, it +only performs some cleanup. + + All right. But did we really need this fake method ? I mean, one +could use the usual mail method, and simply not send the message in the +end. Huh, yeah, ok... Actually, it is very probable that in a future +release of Patcher, the mail buffer won't be the master buffer anymore, +and mail sending will be just another optional step in the process. In +that case, the mail method is likely to move away from project option +to standard user option. + + +File: patcher.info, Node: Other Mail Methods, Prev: Fake Mail Method, Up: Mail Methods + +Other Mail Methods +.................. + +If you're not satisfied with the provided mail methods (want a `vm' one +?), you can provide your own, more or less. Here's what to do: set your +`:mail-method' project option to, say, `foo', and write your own +function which must be named `patcher-mail-foo'. + + This function must take two arguments (a project descriptor and a +string containing the subject of the message), and prepare a mail +buffer. If you want to do this, you should see how it's done for the +built-in methods. + + Note that the mail adaptation facility won't be available for your +custom method. For that, I would have to hack the internals of Patcher. + + +File: patcher.info, Node: Message Customization, Prev: Mail Methods, Up: Mail Preparation + +Message Customization +--------------------- + +When preparing a message, Patcher can fill some parts of it for you. +Here's a list of mail-related project options. + +`:user-name' + The name (your name) to use when composing the message. It will + affect the `From:' header. This option is used by all mail methods + but `fake'. If not given, `user-full-name' is used. + +`:user-mail' + The mail (your mail) address to use when composing the message. It + will affect the `From:' header. This option is used by all mail + methods but `fake'. If not given, `user-mail-address' is used. + +`:to-address' + The address to send messages to (a string). This option is used by + all mail methods but `gnus' and `fake'. If not given, it is + prompted for when calling `patcher-mail'. + +`:gnus-group' + The Gnus group name to use for posting messages (a string). This + option is used only by the `gnus' mail method. If not given, it is + prompted for when calling `patcher-mail'. + + Note that if you configured your name and mail in Gnus, for + instance through posting styles, these configurations take + precedence over the corresponding Patcher options. + +`:subject-prefix' + A prefix for the subject line of messages. It can be `nil' or a + string. By default, "[PATCH]" is used. This part of subjects is + never prompted for. A `%n' occurring in this string will be + replaced with the project name. Also, a space is inserted between + the prefix and the remainder of the subject, when appropriate. + +`:subject' + A default value for prompted subjects (a string). A `%n' occurring + in this string will be replaced with the project's name (*note + Subproject Naming::). Please note that this is used *only* to + provide a default value for prompted subjects. Subjects are + *always* prompted for. + +`:mail-prologue' + A prologue to insert just at the top of a message body (a string). + + +File: patcher.info, Node: Patch Generation, Next: ChangeLogs Handling, Prev: Mail Preparation, Up: User Manual + +Patch Generation +================ + +Patcher creates patches by diffing your local copy of the project +against the repository. This is done automatically after preparing a +message, so you shouldn't normally bother to do it manually. That +situation might still happen from time to time, like, if you further +modify the sources, or if the initial operation failed for some reason +(*note More On Commands::). + + The way to (re)generate the patch manually is to call +`patcher-generate-diff' from the mail buffer. This function is bound to +`C-c C-p d' in this buffer. You can both customize the diff command +used to (re)generate the patch, and restrict the diff to a subset of +the project's files. + + When possible, Patcher also tries to check that your project is +up-to-date with respect to the archive, and will inform you otherwise. + +* Menu: + +* Diff Command:: Specifying the command to generate the patch +* After Diff Hook:: Tweaking the diff output +* Diff Line Filter:: Omitting lines from the diff output +* Patch Restriction:: Specifying the files affected by the patch +* Patcher Instances:: You can have several instances of Patcher +* Diff Prologue:: A header is inserted above the patch + + By the way, (re)generating the patch does not necessarily mean that +it is directly inserted into the mail buffer. This also depends on the +ChangeLogs behavior (*note ChangeLogs Handling::). + + +File: patcher.info, Node: Diff Command, Next: After Diff Hook, Prev: Patch Generation, Up: Patch Generation + +Diff Command +------------ + +The diff command used to generate the patch is specified by the +`:diff-command' project option. By default, the command used is `cvs -q +diff -u'. You can also punctually change this command by calling +`patcher-mail' or `patcher-generate-diff' with a prefix argument. +Patcher will then prompt you for a new command and use it exclusively +for this particular patch. + + For detail about the format of this option, see *Note Patch +Restriction::. See also *Note More On Commands::. + + +File: patcher.info, Node: After Diff Hook, Next: Diff Line Filter, Prev: Diff Command, Up: Patch Generation + +After Diff Hook +--------------- + +Sometimes, you might want to tweak a little the diff output before doing +anything with it, for instance, before generating ChangeLog skeletons +(*note ChangeLogs Handling::), or simply inserting it into the mail +buffer. + + In order to do that, you might want to use the `:after-diff-hook' +project option. It should be a list of function names (symbols) that +will be called after each diff output. Each function should take two +optional arguments delimiting a region to process (no arguments means +process the whole buffer) and work in the current buffer. The point is +originally placed at the beginning of the region, and the buffer +excursion is saved for you. + + Note: Patcher provides a special function named +`patcher-prcs-diff-convert' that can be used in this hook in order to +convert PRCS diff output to a traditional one. + + +File: patcher.info, Node: Diff Line Filter, Next: Patch Restriction, Prev: After Diff Hook, Up: Patch Generation + +Diff Line Filter +---------------- + +When generating a global diff, that is, without specifying the files +affected by the patch explicitly (*note Patch Restriction::), some +uninformative lines might be present in the output. A typical example is +files present in your local copy but unknown to the CVS server. Such +files are indicated by a question mark in diff outputs. + + Patcher has a project option named `:diff-line-filter' that lets +filter out such unwanted lines when inserting the diff in the mail +buffer. This must be a regular expression matching a whole line. Caution +however: do not put beginning or end of lines markers in your regexp. +Patcher will do it for you. + + By default, the value is `"\\? .*"', which excludes files unknown to +the CVS server. + + +File: patcher.info, Node: Patch Restriction, Next: Patcher Instances, Prev: Diff Line Filter, Up: Patch Generation + +Patch Restriction +----------------- + +Sometimes, you don't want to generate a global patch, but instead work +on a subset of the project's files. Patcher understands this concept as +working on a "subproject". + + As for working on whole projects, there are several alternatives to +start working on a subproject: + + - Function: patcher-mail-subproject + This function behaves exactly like `patcher-mail', except that it + also prompts you for the files affected by the patch. You can + specify files as well as directories, use wildcards, just as you + would construct a command line diff. + + - Function: patcher-mail-adapt-subproject + Idem, with respect to `patcher-mail-adapt'. + + Finally, all the Gnus-specific reply functions (*note Mail +Preparation::) take an optional prefix argument that make them work on +subprojects. + + Two important things are to be kept in mind when working on +subprojects: + * It is not necessary (it is even forbidden) to specify the ChangeLog + files. Patcher will automatically find them for you. In other + words, only specify source files, not ChangeLog files. + + * Don't mistake the prefix argument of `patcher-mail', + `patcher-mail-subproject' and `patcher-generate-diff' as a way to + specify files. It is not meant for that. It is meant only to + temporarily modify the diff command itself, not the files to which + it applies. + + When working on a subproject, Patcher uses the same diff command as +the one used for the whole project, that is, the value of the +`:diff-command' project option. In the case of a subproject however, +Patcher has to know where to put the files on the command line (even if +it's usually the last part of it). This is done with the special +construct `%f': a `%f' appearing in the diff command will be replaced +with the specified files (and the computed ChangeLog files) for a +subproject, and will simply be removed when working on the whole +project. + + As an example, given that the default diff command used by Patcher is +`cvs -q diff -u', you should know understand that the default value for +`patcher-default-diff-command' is `cvs -q diff -u %f'. Do you ? + + There is another special construct available in this command: a `%n' +will be replaced with the project's name (*note Subproject Naming::). +This is useful in commands with weird options syntax, like PRCS. + + For a more advanced way of handling subprojects, see *Note More On +Subprojects::. + + +File: patcher.info, Node: Patcher Instances, Next: Diff Prologue, Prev: Patch Restriction, Up: Patch Generation + +Patcher Instances +----------------- + +The concept of subprojects brings up the question of having Patcher +working on different patches at the same time. It is possible under some +conditions: + + * You can have as many simultaneous Patcher instances as you want on + different projects (you would not define two projects sharing the + same directory, would you ?). + + * You can have as many simultaneous Patcher instances as you want on + the same project, as long as there is no overlapping between each + subproject. This means that you can't have source files, or even + ChangeLog files in common. + + This last point will be subject to improvements in the future. + + +File: patcher.info, Node: Diff Prologue, Prev: Patcher Instances, Up: Patch Generation + +Diff Prologue +------------- + +Patcher can (and does) insert a special prologue just above a patch in +the message in preparation. This prologue gives information such as the +diff command used, the files affected and so on. + + The function used to generate this prologue can be specified with the +`:diff-prologue-function' project option. A value of `nil' means don't +insert any prologue. By default, the internal function +`patcher-default-diff-prologue' is used. If you want to provide your +own, here how to do it. + + Your function should take one argument indicating the kind of diff (a +symbol), and perform insertion at current point in the current buffer. +The possible values for the argument are: + +`sources' + indicates a source diff only, + +`change-logs' + indicates a ChangeLog diff only, + +`mixed' + indicates a diff on both source and ChangeLog files. + + The following variables are bound (when appropriate) when this +function is executed: + +`name' + the name of the current Patcher project, + +`source-diff' + the command used to create a source diff, + +`change-log-diff' + the command used to create a ChangeLog diff, + +`source-files' + sources files affected by the current patch, + +`change-log-files' + ChangeLog files affected by the current patch. + + In the case of a mixed diff, a `nil' value for `change-log-diff' +indicates that the same command was used for both the source and +ChangeLog files. + + +File: patcher.info, Node: ChangeLogs Handling, Next: Project Check In, Prev: Patch Generation, Up: User Manual + +ChangeLogs Handling +=================== + +ChangeLogs management in Patcher involves two aspects: how ChangeLog +entries are created, and how they appear in the messages. Both aspects +can be customized beyond your craziest dreams. + +* Menu: + +* ChangeLogs Updating:: How Patcher deals with ChangeLogs +* ChangeLogs Appearance:: How ChangeLogs appear in messages +* ChangeLogs Prologue:: A header is inserted above the ChangeLogs + + +File: patcher.info, Node: ChangeLogs Updating, Next: ChangeLogs Appearance, Prev: ChangeLogs Handling, Up: ChangeLogs Handling + +ChangeLogs Action +----------------- + +The way Patcher deals with ChangeLogs is controlled via the +`:change-logs-updating' project option. Its value must be a symbol from +the following: + +`automatic' + This is the default. Each time you (re)generate a diff, Patcher + (re)creates ChangeLog skeletons in the appropriate ChangeLog + files, by analyzing the generated diff. You then have to fill the + entries manually. *Caution*: the diff analysis is not done by + Patcher directly, but by the function `patch-to-change-log' from + the `add-log' library from the `xemacs-base' package. Only + standard diff and cvs diff output are currently supported, both in + unified format only. + +`manual' + Patcher assumes that you create ChangeLog entries manually, as you + write code, so it won't create ChangeLogs skeletons. It is + important to understand that in this situation, ChangeLog entries + *must* have been written *before* you call Patcher. Patcher won't + let you write them in the process. + +`none' + The project doesn't have ChangeLog files. Patcher won't try to + create ChangeLog entries, and won't expect that you have written + some either. + + If you're working in `automatic' updating mode, Patcher has two +other project options that give you some control on the created entries: +`:change-logs-user-name' and `:change-logs-user-mail'. As you might +expect, these are strings defining your name and mail address for +ChangeLog entries'headers. When `nil', Patcher lets the function +`patch-to-change-log' decide what to use (most probably what the user +options `user-full-name' and `user-mail-address' say). + + Here's a last point to mention about the `automatic' updating mode. +In order to build the ChangeLog skeletons, the source files must be +visited. Patcher has a `:kill-source-files-after-diffing' project +option that lets you decide whether you want to kill the source buffers +just after diffing or not. The value can be either `nil' or `t'. By +default, the behavior is to preserve the source files, since you might +need them for reference when filling the ChangeLog entries. + + If you're working in `manual' updating mode, Patcher might still +need to know the affected ChangeLog files (for the commit process) and +your exact ChangeLog entries in each of these files (for insertion in +the message). The ChangeLog files are automatically deduced from the +patch. When that's required, however, you will be presented with each +ChangeLog file in turn, and invited to precise the number of ChangeLog +entries concerning this patch. These entries must of course appear at +the top of the file. + + Finally, note that an updating mode of `none' is the only case where +ChangeLog files are regarded as normal ones if present. As a +consequence, that is a case where it is not forbidden to list them +explicitly as part of a subproject (*note Patch Restriction::), +although I don't see why you would want to do that. + + +File: patcher.info, Node: ChangeLogs Appearance, Next: ChangeLogs Prologue, Prev: ChangeLogs Updating, Up: ChangeLogs Handling + +ChangeLogs Appearance +--------------------- + +When Patcher has to deal with ChangeLog files, you insert ChangeLog +entries in the message buffer by calling the function +`patcher-insert-change-logs'. It is bound to `C-c C-p i' in the mail +buffer. Note that if ChangeLogs are written in advance, you don't have +to do that, as Patcher will do it automatically. You have to call this +function by hand only in `automatic' updating mode (*note ChangeLogs +Updating::). + + In all circumstances however, you can use this function to +*reinsert* the ChangeLog entries into the mail buffer. That might come +in handy if you further modified them after the initial insertion (it's +never too late to fix a typo). + + The appearance of ChangeLog entries in the message is controlled by +the `:change-logs-appearance' project option. Its value must be a +symbol from the following: + +`verbatim' + This is the default. ChangeLog entries appear just as text in the + message, above the patch. Most people prefer this kind of + appearance since it is the most readable. + +`packed' + ChangeLog entries appear as a patch (they are diff'ed against the + archive). This patch is however distinct from the source patch, and + appears above it. + +`patch' + ChangeLog entries appear as a patch (they are diff'ed against the + archive), and this patch is integrated into the source patch. In + other words, the message looks like a global patch integrating + both the sources and the ChangeLogs. + + When the ChangeLogs appearance is either `packed' or `patch', the +diff command used to generate the patch is controlled by the +`:change-logs-diff-command' project option. The value can be the symbol +`diff', meaning that the same diff command is to be used as for the +sources (*note Diff Command::), or it can be a string specifying an +alternate command. + + When diffing ChangeLog files, it is strongly recommended that you +remove contexts from the diff, because otherwise, ChangeLog patches +often fail to apply correctly. + + As in the case of the `:diff-command' project option (*note Patch +Restriction::), a `%f' serves to indicate where to put the ChangeLog +files on the diff command line, and a `%n' is replaced with the +project's name (*note Subproject Naming::). See also *Note More On +Commands::. + + Given these two remarks, you should now understand why the default +value for `patcher-default-change-logs-diff-command' is `cvs -q diff -U +0 %f'. + + +File: patcher.info, Node: ChangeLogs Prologue, Prev: ChangeLogs Appearance, Up: ChangeLogs Handling + +ChangeLogs Prologue +------------------- + +ChangeLog prologues are small pieces of informative text that Patcher +adds above each ChangeLog insertion in the mail buffer. + + When the ChangeLogs appearance is `verbatim', Patcher inserts one +prologue per ChangeLog file. The prologue's contents is controlled by +the `:change-logs-prologue' project option (a string). A `%f' appearing +in this string will be replaced with the ChangeLog filename. The +default value for `patcher-default-change-logs-prologue' is `"%f +addition:"'. + + When the ChangeLogs appearance is `packed', Patcher inserts only one +prologue for the whole ChangeLogs patch. When `patch', there is a +single prologue for both the ChangeLogs and the sources. For +customizing the prologue in both of these cases, see *Note Diff +Prologue::. + + +File: patcher.info, Node: Project Check In, Next: Mail Sending, Prev: ChangeLogs Handling, Up: User Manual + +Project Check In +================ + +If you have the privilege to commit your changes yourself, you might do +so directly from the mail buffer, as the last operation before actually +sending the message. This is done by calling the function +`patcher-commit-change' which is bound to `C-c C-p c' in the mail +buffer. + + Committing directly from Patcher has the advantage that both the +commit command line and the commit log message (*note Log Message +Handling::) are constructed automatically. Of course, you still have an +in-depth control on the commit process. + +* Menu: + +* Commit Command:: Specifying the command to commit the patch +* Log Message Handling:: Building a commit log message +* Commit Operation:: Actually committing your changes + + +File: patcher.info, Node: Commit Command, Next: Log Message Handling, Prev: Project Check In, Up: Project Check In + +Commit Command +-------------- + +The command used to to commit a patch is specified by the +`:commit-command' project option (a string). You can also temporarily +change the command in question by calling `patcher-commit-change' with +a prefix argument. As usual, note that this prefix argument is not +meant to modify the affected files on the command line. It's meant only +to punctually modify the commit command itself. The affected files are +computed automatically by Patcher. + + The commit command accepts (and maybe requires) special constructs: + + * A `%n' occurring in the string will be replaced with the project's + name (*note Subproject Naming::). + + * A `%f' occurring in the string will be replaced with the files + affected by the patch (ChangeLogs included, this time), or + discarded if the patch is global. + + * A `%s' occurring in the string will be replaced with the name of a + file containing the commit log message (*note Log Message + Handling::). This file is a temporary file handled by Patcher. + + * A `%S' occurring in the string will be replaced with the commit log + message itself (*note Log Message Handling::). Since the intent + here is to use the message as a command-line argument, it is + quoted against shell expansion. + + Please note that a `%f' is required in your commit commands, unless +you know for sure that you will never ever work on a subproject (*note +Patch Restriction::). But you never know that. Besides, you should +always also provide either a `%s' or a `%S', unless your archival +software does not support log messages. + + Given that, you should now understand why the default value for +`patcher-default-commit-command' is `cvs commit -F %s %f'. + + +File: patcher.info, Node: Log Message Handling, Next: Commit Operation, Prev: Commit Command, Up: Project Check In + +Log Message Handling +-------------------- + +Most project management tools understand the concept of a "log +message": a short yet informative message that accompany the commit +operation, which is also stored in the repository. + + Before a commit operation, Patcher always builds an initial log +message, based on certain elements under your control (*note Log +Message Elements::). Afterwards, you can decide on whether you want +some further (manual) edition of log message, or whether you want to +commit immediately. + + The `:edit-log-message' project option lets you specify this +behavior. If `t' (the default), you will be able to manually edit the +log message. If `nil', Patcher will proceed directly to the commit +operation. + + Please note that Patcher stores log messages in temporary files that +will be used later by the commit command. + +* Menu: + +* Log Message Elements:: Elements Patcher can add automatically +* Log Message Editing:: Manually modifying the log message + + +File: patcher.info, Node: Log Message Elements, Next: Log Message Editing, Prev: Log Message Handling, Up: Log Message Handling + +Log Message Elements +.................... + +Patcher has the ability to initialize the log message with different +elements. These elements are specified with the `:log-message-items' +project option. Its value is either `nil', meaning that you don't want +any initialization, or a list of symbols specifying the elements you +desire. The available items are: + +`subject' + The subject of the message. The subject's prefix is automatically + removed. + +`compressed-change-logs' + The "compressed" ChangeLog entries. Only the most important part of + the ChangeLogs is preserved, so the entries appear in a more + compact fashion. + +`change-logs' + The raw ChangeLog entries. + + By default, only the message's subject is used. When using more than +one item, they appear in the order specified above. If anything appears +before the raw ChangeLog entries, a separator string is used. This +string is specified by the `:change-logs-separator' project option. By +default the string looks like "-- ChangeLog entries follow: --". + + +File: patcher.info, Node: Log Message Editing, Prev: Log Message Elements, Up: Log Message Handling + +Log Message Editing +................... + +If so required, Patcher lets you manually edit the log message after +having initialized it. Log message edition happens in a special buffer, +the `*Patcher Log Message*' buffer. + + While editing this buffer, commands to insert the items described in +*Note Log Message Elements:: are at your disposal. These commands +perform insertion at point: + +`patcher-logmsg-insert-subject' + Bound to `C-c C-p s'. Insert the message's subject (sans the + prefix). + +`patcher-logmsg-insert-compressed-change-logs' + Bound to `C-c C-p c'. Insert the compressed ChangeLog entries. + +`patcher-logmsg-insert-change-logs' + Bound to `C-c C-p l'. Insert the raw ChangeLog entries. Use a + prefix argument if you also want the ChangeLogs separator string + to be inserted. + + In addition to these commands, you can also completely reinitialize +the log message according to the specified items, by calling the +function `patcher-logmsg-init-message', bound to `C-c C-p i'. Caution: +this command first erases the buffer. + + Finally, once you're happy with your log message, you proceed to the +commit operation by calling the function `patcher-logmsg-commit', bound +to `C-c C-c'. + + +File: patcher.info, Node: Commit Operation, Prev: Log Message Handling, Up: Project Check In + +Commit Operation +---------------- + +The commit operation occurs after typing `C-c C-p c' from the mail +buffer, if you have not required log message edition, or after typing +`C-c C-c' from the `*Patcher Log Message*' buffer otherwise. + + At that point, Patcher has constructed a proper commit command. You +still have an option to abort the process, though: the +`:confirm-commits' project option lets you specify whether to require +confirmation before committing. If `t' (the default), Patcher will +display the constructed commit command and ask for a confirmation +before proceeding. If `nil', Patcher will commit immediately. + + After the commit operation, Patcher changes some parts of the mail +buffer in the following manner: + + * The subject prefix is changed to that specified by the + `:subject-committed-prefix' project option (a string), unless it is + `nil'. By default, "[COMMIT]" is used. + + * A commit notice is added right at the beginning of the message's + body. This notice is specified by the `:committed-notice' project + option. It can be `nil' or a string. By default, it reads "NOTE: + this patch has been committed.". + + +File: patcher.info, Node: Mail Sending, Next: More On Commands, Prev: Project Check In, Up: User Manual + +Mail Sending +============ + +Sending the message will most probably be done by typing `C-c C-c' in +the mail buffer. This is also the case when you're using the fake mail +method, by the way. + +* Menu: + +* Before Sending:: Patcher does some checkings +* After Sending:: patcher does some cleanup + + +File: patcher.info, Node: Before Sending, Next: After Sending, Prev: Mail Sending, Up: Mail Sending + +Before Sending +-------------- + +There are circumstances in which Patcher will perform some checkings on +your message when you send it, just before it is actually sent: + + * ChangeLogs insertion + + In case of manual ChangeLog insertion (*note ChangeLogs + Appearance::), Patcher can check that you have indeed inserted the + ChangeLog entries before sending the message. This behavior is + controlled by the `patcher-mail-check-change-logs-insertion' user + option. A value of `nil' means never check (the message will be + sent as-is). A value of t means check, and abort the sending if + the ChangeLog entries are missing. A value of `ask' (the default) + means ask for your opinion on this terrible matter. + + * Commit Operation + + Patcher has a `:commit-privilege' project option; a boolean + specifying whether you're likely to commit your changes by + yourself. + + In case of commit privilege, Patcher can check that you have indeed + committed your changes before sending the message. This behavior is + controlled by the `patcher-mail-check-commit-action' user option. A + value of `nil' means never check (the message will be sent as-is). + A value of t means check, and abort the sending if the commit + operation has not been performed. A value of `ask' (the default) + means ask for your opinion on this rather unfortunate situation. + + Two notes on these checkings: + + * For uninteresting technical reasons, Patcher does not currently + (and will probably never) offer you an automatic ChangeLogs + insertion or commit operation, at mail sending time, but just + abort the sending process in some circumstances. That's not a big + deal though. + + * For other uninteresting technical reasons, these checkings require + a native knowledge of your mail user agent. Patcher does not + currently support all mail user agents on earth (I'll add them on + demand however). If that's the case, you will be warned and + invited to send me a message. Also, you can send me one on April + 21st: it's my birthday. + + +File: patcher.info, Node: After Sending, Prev: Before Sending, Up: Mail Sending + +After Sending +------------- + +After sending the message, Patcher also performs some cleanup +operations, that you can customize. The cleanup is controlled by the +following project options. Each one is a boolean option which defaults +to `t'. + +`:kill-source-files-after-sending' + Whether to kill source files after sending the message. If `nil', + the source files will remain visited. + +`:kill-change-logs-after-sending' + Whether to kill ChangeLog files after sending the message. If + `nil', the ChangeLog files will remain visited. + + +File: patcher.info, Node: More On Commands, Next: More On Subprojects, Prev: Mail Sending, Up: User Manual + +More On Commands +================ + +This section deals with information that apply to all commands used by +Patcher (diff and commit operations). + +* Menu: + +* Prefixing Commands:: Bypassing a firewall +* Error Handling:: Dealing with errors + + +File: patcher.info, Node: Prefixing Commands, Next: Error Handling, Up: More On Commands + +Prefixing Commands +------------------ + +If you're working on a distant archive and you're behind a firewall, you +might need to prefix all your commands with something like `runsocks'. +Of course, this can be done manually in all your command settings, but +Patcher offers you a simpler way to do it. + + There is a project option named `:pre-command' which can be used for +this kind of thing. It must be a string that will be prepended to all +operations performed by Patcher. + + +File: patcher.info, Node: Error Handling, Prev: Prefixing Commands, Up: More On Commands + +Error Handling +-------------- + +From time to time, commands may fail for different reasons. Patcher +tracks the failures in these commands and lets you know when that +happens. The `:failed-command-regexp' project option lets you specify a +regular expression to match with the output of an aborted command. By +default, the value is `"^cvs \\[[^]]* aborted\\]"'. + + +File: patcher.info, Node: More On Subprojects, Prev: More On Commands, Up: User Manual + +More On Subprojects +=================== + +We've already seen how to work punctually on a subproject, that is, on a +subset of a project's files (*note Patch Restriction::). If you happen +to work more than once on the same project subset, it will quickly +become annoying to have to specify explicitly the same files over and +over again. Patcher offers you a way to permanently define subprojects. + +* Menu: + +* Defining Subprojects:: Storing subprojects definitions +* Subproject Naming:: When different projects have the same name +* Command Directory:: For non local revision control systems + + +File: patcher.info, Node: Defining Subprojects, Next: Subproject Naming, Up: More On Subprojects + +Defining Subprojects +-------------------- + +The user option `patcher-subprojects' stores a list of "subproject +descriptors". A subproject descriptor is almost the same as a project +descriptor, with a few exceptions: + + * Instead of the project directory field (the second field in a + project descriptor), you rather specify the name of the project + this subproject is based on. + + * In addition to the standard project options we've already seen, two + subproject options are available: + `:subdirectory' + This lets you specify a subdirectory of the original + project's directory in which the whole subproject resides. + + `:files' + This lets you specify a list of files or directories + composing the subproject. Each file specification can contain + wildcards. If a `:subdirectory' subproject option is given, + these files or directories should be relative to this + subdirectory. Otherwise, they should be relative to the + parent project's directory. + + Please note that these subproject options have no corresponding + fallback (that would be meaningless). They can't appear in a theme + either. + + * Subprojects don't have an `:inheritance' mechanism. Instead, they + implicitly inherit from their base project (which in turn can + inherit from other projects). + + Here are some important remarks about subprojects: + + * A subproject with neither a `:subdirectory' nor a `:files' option + is exactly the same as the base project, apart from project + options that you would override. + + * Since permanent subprojects are defined statically, they should be + used with the normal Patcher functions like `patcher-mail'. You + don't need to use the `*-subproject' versions any more. + + * Because of that, projects and subprojects can't have names in + common. If that happens to be the case, Patcher will blindly use a + subproject rather than a project of that name + + * So what happens if you persist in using a `*-subproject' function + on a permanent subproject ? Well, you punctually work on a + subsubproject... + + +File: patcher.info, Node: Subproject Naming, Next: Command Directory, Prev: Defining Subprojects, Up: More On Subprojects + +Subproject Naming +----------------- + +As you already know, Patcher distinguishes projects by their NAME field +in the `patcher-projects' and `patcher-subprojects' user options. This +is problematic, however, if you define different patcher projects for a +single physical project, and the commands require the project's name. +That might for instance be the case with PRCS (decidedly) weird options +syntax. + + To remedy this problem, patcher provides a `:name' project option. +If set, it will actually be used for all `%n' substitutions where the +project's name (in the Patcher sense) would normally be used. + + If you want to use the project's name in the Patcher sense, +regardless of the value of the `:name' option, use `%N' instead of `%n'. + + +File: patcher.info, Node: Command Directory, Prev: Subproject Naming, Up: More On Subprojects + +Command Directory +----------------- + +Some revision control systems, like CVS, work on a per-file basis. Some +others, like PRCS, work only globally. This has an important implication +for subprojects being sudirectories of other projects. Indeed, while +CVS, for instance, can be executed anywhere, PRCS can only be run in the +base project's root directory. + + If you want to define projects for which the revision control system +can be executed in only one directory, Patcher provides you with the +`:command-directory' project option (a string). This directory can be +specified relative to the project's directory (but note that it must go +upwards). + + All commands (diff and commit ones) will be executed from there. +Also, note that the command directory does not change the way you might +specify files. Patcher modifies all needed paths automatically to handle +the command directory properly. + + +File: patcher.info, Node: Variables Index, Next: Functions Index, Prev: User Manual, Up: Top + +Variables Index +*************** + +* Menu: + +* :after-diff-hook: After Diff Hook. +* :change-logs-appearance: ChangeLogs Appearance. +* :change-logs-diff-command: ChangeLogs Appearance. +* :change-logs-prologue: ChangeLogs Prologue. +* :change-logs-separator: Log Message Elements. +* :change-logs-updating: ChangeLogs Updating. +* :change-logs-user-mail: ChangeLogs Updating. +* :change-logs-user-name: ChangeLogs Updating. +* :command-directory: Command Directory. +* :commit-command: Commit Command. +* :commit-privilege: Before Sending. +* :committed-notice: Commit Operation. +* :confirm-commits: Commit Operation. +* :diff-command <1>: ChangeLogs Appearance. +* :diff-command <2>: Diff Command. +* :diff-command: Patch Restriction. +* :diff-line-filter: Diff Line Filter. +* :diff-prologue-function <1>: ChangeLogs Prologue. +* :diff-prologue-function: Diff Prologue. +* :edit-log-message: Log Message Handling. +* :failed-command-regexp: Error Handling. +* :files: Defining Subprojects. +* :gnus-group <1>: Standard Mail Methods. +* :gnus-group: Message Customization. +* :inheritance <1>: Project inheritance. +* :inheritance <2>: Retrieval. +* :inheritance: Defining Subprojects. +* :kill-change-logs-after-sending: After Sending. +* :kill-source-files-after-diffing: ChangeLogs Updating. +* :kill-source-files-after-sending: After Sending. +* :log-message-items: Log Message Elements. +* :mail-method <1>: Other Mail Methods. +* :mail-method: Mail Methods. +* :name: Subproject Naming. +* :pre-command: Prefixing Commands. +* :subdirectory: Defining Subprojects. +* :subject: Message Customization. +* :subject-committed-prefix: Commit Operation. +* :subject-prefix: Message Customization. +* :themes <1>: Retrieval. +* :themes: Themes. +* :to-address <1>: Fallbacks. +* :to-address <2>: Message Customization. +* :to-address <3>: Project Descriptors. +* :to-address: Calling Patcher. +* :user-mail: Message Customization. +* :user-name: Message Customization. +* mail-user-agent: Standard Mail Methods. +* patcher-default-after-diff-hook: After Diff Hook. +* patcher-default-change-logs-appearance: ChangeLogs Appearance. +* patcher-default-change-logs-diff-command: ChangeLogs Appearance. +* patcher-default-change-logs-prologue: ChangeLogs Prologue. +* patcher-default-change-logs-separator: Log Message Elements. +* patcher-default-change-logs-updating: ChangeLogs Updating. +* patcher-default-change-logs-user-mail: ChangeLogs Updating. +* patcher-default-change-logs-user-name: ChangeLogs Updating. +* patcher-default-command-directory: Command Directory. +* patcher-default-commit-command: Commit Command. +* patcher-default-commit-privilege: Before Sending. +* patcher-default-committed-notice: Commit Operation. +* patcher-default-confirm-commits: Commit Operation. +* patcher-default-diff-command <1>: ChangeLogs Appearance. +* patcher-default-diff-command <2>: Patch Restriction. +* patcher-default-diff-command: Diff Command. +* patcher-default-diff-line-filter: Diff Line Filter. +* patcher-default-diff-prologue-function <1>: ChangeLogs Prologue. +* patcher-default-diff-prologue-function: Diff Prologue. +* patcher-default-edit-log-message: Log Message Handling. +* patcher-default-failed-command-regexp: Error Handling. +* patcher-default-gnus-group <1>: Standard Mail Methods. +* patcher-default-gnus-group: Message Customization. +* patcher-default-kill-change-logs-after-sending: After Sending. +* patcher-default-kill-source-files-after-diffing: ChangeLogs Updating. +* patcher-default-kill-source-files-after-sending: After Sending. +* patcher-default-log-message-items: Log Message Elements. +* patcher-default-mail-method <1>: Mail Methods. +* patcher-default-mail-method: Other Mail Methods. +* patcher-default-name: Subproject Naming. +* patcher-default-pre-command: Prefixing Commands. +* patcher-default-subject: Message Customization. +* patcher-default-subject-committed-prefix: Commit Operation. +* patcher-default-subject-prefix: Message Customization. +* patcher-default-themes <1>: Retrieval. +* patcher-default-themes: Themes. +* patcher-default-to-address <1>: Fallbacks. +* patcher-default-to-address <2>: Message Customization. +* patcher-default-to-address <3>: Project Descriptors. +* patcher-default-to-address: Calling Patcher. +* patcher-default-user-mail: Message Customization. +* patcher-default-user-name: Message Customization. +* patcher-mail-check-change-logs-insertion: Before Sending. +* patcher-mail-check-commit-action: Before Sending. +* patcher-mail-run-gnus: Standard Mail Methods. +* patcher-mail-run-gnus-other-frame: Standard Mail Methods. +* patcher-max-inheritance-depth: Project inheritance. +* patcher-max-theme-depth: Themes. +* patcher-projects <1>: Project Descriptors. +* patcher-projects <2>: Subproject Naming. +* patcher-projects: Setting up Patcher. +* patcher-subprojects <1>: Subproject Naming. +* patcher-subprojects: Defining Subprojects. +* patcher-themes <1>: Retrieval. +* patcher-themes: Themes. +* user-full-name: ChangeLogs Updating. +* user-mail-address: ChangeLogs Updating. + + +File: patcher.info, Node: Functions Index, Next: Keystrokes Index, Prev: Variables Index, Up: Top + +Functions Index +*************** + +* Menu: + +* compose-mail: Standard Mail Methods. +* gnus-post-news: Standard Mail Methods. +* mail: Standard Mail Methods. +* message-mail: Standard Mail Methods. +* patch-to-change-log: ChangeLogs Updating. +* patcher-commit-change <1>: Commit Command. +* patcher-commit-change <2>: Committing the Patch. +* patcher-commit-change: Project Check In. +* patcher-default-diff-prologue <1>: Diff Prologue. +* patcher-default-diff-prologue: ChangeLogs Prologue. +* patcher-generate-diff <1>: Patch Generation. +* patcher-generate-diff: Patch Restriction. +* patcher-gnus-summary-followup <1>: Mail Preparation. +* patcher-gnus-summary-followup: Patch Restriction. +* patcher-gnus-summary-followup-with-original <1>: Patch Restriction. +* patcher-gnus-summary-followup-with-original: Mail Preparation. +* patcher-gnus-summary-reply <1>: Mail Preparation. +* patcher-gnus-summary-reply: Patch Restriction. +* patcher-gnus-summary-reply-with-original <1>: Mail Preparation. +* patcher-gnus-summary-reply-with-original: Patch Restriction. +* patcher-insert-change-logs <1>: Filling the Message. +* patcher-insert-change-logs: ChangeLogs Appearance. +* patcher-logmsg-commit <1>: Committing the Patch. +* patcher-logmsg-commit: Log Message Editing. +* patcher-logmsg-init-message: Log Message Editing. +* patcher-logmsg-insert-change-logs: Log Message Editing. +* patcher-logmsg-insert-compressed-change-logs: Log Message Editing. +* patcher-logmsg-insert-subject: Log Message Editing. +* patcher-mail <1>: Calling Patcher. +* patcher-mail <2>: Diff Command. +* patcher-mail <3>: Patch Restriction. +* patcher-mail <4>: Mail Preparation. +* patcher-mail: Defining Subprojects. +* patcher-mail-adapt <1>: Mail Preparation. +* patcher-mail-adapt <2>: Patch Restriction. +* patcher-mail-adapt: Defining Subprojects. +* patcher-mail-adapt-subproject <1>: Patch Restriction. +* patcher-mail-adapt-subproject: Defining Subprojects. +* patcher-mail-compose-mail: Standard Mail Methods. +* patcher-mail-fake: Fake Mail Method. +* patcher-mail-gnus: Standard Mail Methods. +* patcher-mail-message: Standard Mail Methods. +* patcher-mail-sendmail: Standard Mail Methods. +* patcher-mail-subproject <1>: Defining Subprojects. +* patcher-mail-subproject: Patch Restriction. +* patcher-prcs-diff-convert: After Diff Hook. + + +File: patcher.info, Node: Keystrokes Index, Prev: Functions Index, Up: Top + +Keystrokes Index +**************** + +* Menu: + +* C-c C-c <1>: Log Message Editing. +* C-c C-c <2>: Commit Operation. +* C-c C-c: Committing the Patch. +* C-c C-p c <1>: Log Message Editing. +* C-c C-p c <2>: Commit Operation. +* C-c C-p c <3>: Committing the Patch. +* C-c C-p c: Project Check In. +* C-c C-p d: Patch Generation. +* C-c C-p F: Mail Preparation. +* C-c C-p f: Mail Preparation. +* C-c C-p i <1>: Filling the Message. +* C-c C-p i <2>: Log Message Editing. +* C-c C-p i: ChangeLogs Appearance. +* C-c C-p l: Log Message Editing. +* C-c C-p r: Mail Preparation. +* C-c C-p R: Mail Preparation. +* C-c C-p s: Log Message Editing. + + + +Tag Table: +Node: Top1225 +Node: Copying2018 +Node: Introduction2706 +Node: Installation5071 +Node: Distribution5395 +Node: Requirements6728 +Node: Insinuation7862 +Node: Quick Start8479 +Node: Setting up Patcher9637 +Node: Calling Patcher10781 +Node: Filling the ChangeLogs12410 +Node: Filling the Message12911 +Node: Committing the Patch13647 +Node: Sending the Message15352 +Node: User Manual16244 +Node: Project Descriptors17185 +Node: Themes18518 +Node: Project inheritance19810 +Node: Fallbacks21011 +Node: Retrieval21935 +Node: Inheritance or theme ?23405 +Node: Mail Preparation24321 +Node: Mail Methods26698 +Node: Standard Mail Methods27260 +Node: Fake Mail Method30207 +Node: Other Mail Methods31399 +Node: Message Customization32156 +Node: Patch Generation34201 +Node: Diff Command35727 +Node: After Diff Hook36349 +Node: Diff Line Filter37328 +Node: Patch Restriction38214 +Node: Patcher Instances40791 +Node: Diff Prologue41593 +Node: ChangeLogs Handling43117 +Node: ChangeLogs Updating43662 +Node: ChangeLogs Appearance46762 +Node: ChangeLogs Prologue49348 +Node: Project Check In50254 +Node: Commit Command51118 +Node: Log Message Handling52966 +Node: Log Message Elements54066 +Node: Log Message Editing55235 +Node: Commit Operation56556 +Node: Mail Sending57814 +Node: Before Sending58216 +Node: After Sending60425 +Node: More On Commands61056 +Node: Prefixing Commands61414 +Node: Error Handling61983 +Node: More On Subprojects62438 +Node: Defining Subprojects63128 +Node: Subproject Naming65381 +Node: Command Directory66253 +Node: Variables Index67249 +Node: Functions Index73726 +Node: Keystrokes Index76712 + +End Tag Table diff --git a/xemacs-packages/info/pgg.info b/xemacs-packages/info/pgg.info new file mode 100644 index 00000000..016e36db --- /dev/null +++ b/xemacs-packages/info/pgg.info @@ -0,0 +1,431 @@ +This is pgg.info, produced by makeinfo version 4.6 from pgg.texi. + +This file describes the PGG. + + Copyright (C) 2003, 2004 Free Software Foundation, Inc. Copyright +(C) 2001 Daiki Ueno. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation; with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. A copy of the license is included + in the section entitled "GNU Free Documentation License". + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* PGG: (pgg). Emacs interface to various PGP implementations. +END-INFO-DIR-ENTRY + + +File: pgg.info, Node: Top, Next: Overview, Up: (dir) + +PGG +*** + +This manual describes PGG. PGG is an interface library between Emacs +and various tools for secure communication. PGG also provides a simple +user interface to encrypt, decrypt, sign, and verify MIME messages. + +* Menu: + +* Overview:: What PGG is. +* Prerequisites:: Complicated stuff you may have to do. +* How to use:: Getting started quickly. +* Architecture:: +* Parsing OpenPGP packets:: +* Function Index:: +* Variable Index:: + + +File: pgg.info, Node: Overview, Next: Prerequisites, Prev: Top, Up: Top + +Overview +******** + +PGG is an interface library between Emacs and various tools for secure +communication. Even though Mailcrypt has similar feature, it does not +deal with detached PGP messages, normally used in PGP/MIME +infrastructure. This was the main reason why I wrote the new library. + + PGP/MIME is an application of MIME Object Security Services +(RFC1848). The standard is documented in RFC2015. + + +File: pgg.info, Node: Prerequisites, Next: How to use, Prev: Overview, Up: Top + +Prerequisites +************* + +PGG requires at least one implementation of privacy guard system. This +document assumes that you have already obtained and installed them and +that you are familiar with its basic functions. + + By default, PGG uses GnuPG, but Pretty Good Privacy version 2 or +version 5 are also supported. If you are new to such a system, I +recommend that you should look over the GNU Privacy Handbook (GPH) +which is available at `http://www.gnupg.org/gph/'. + + +File: pgg.info, Node: How to use, Next: Architecture, Prev: Prerequisites, Up: Top + +How to use +********** + +The toplevel interface of this library is quite simple, and only +intended to use with public-key cryptographic operation. + + To use PGG, evaluate following expression at the beginning of your +application program. + + (require 'pgg) + + If you want to check existence of pgg.el at runtime, instead you can +list autoload setting for desired functions as follows. + + (autoload 'pgg-encrypt-region "pgg" + "Encrypt the current region." t) + (autoload 'pgg-decrypt-region "pgg" + "Decrypt the current region." t) + (autoload 'pgg-sign-region "pgg" + "Sign the current region." t) + (autoload 'pgg-verify-region "pgg" + "Verify the current region." t) + (autoload 'pgg-insert-key "pgg" + "Insert the ASCII armored public key." t) + (autoload 'pgg-snarf-keys-region "pgg" + "Import public keys in the current region." t) + +* Menu: + +* User Commands:: +* Selecting an implementation:: +* Caching passphrase:: +* Default user identity:: + + +File: pgg.info, Node: User Commands, Next: Selecting an implementation, Up: How to use + +User Commands +============= + +At this time you can use some cryptographic commands. The behavior of +these commands relies on a fashion of invocation because they are also +intended to be used as library functions. In case you don't have the +signer's public key, for example, the function `pgg-verify-region' +fails immediately, but if the function had been called interactively, it +would ask you to retrieve the signer's public key from the server. + + - Command: pgg-encrypt-region start end recipients &optional sign + Encrypt the current region between START and END for RECIPIENTS. + When the function were called interactively, you would be asked + about the recipients. + + If encryption is successful, it replaces the current region + contents (in the accessible portion) with the resulting data. + + If optional argument SIGN is non-`nil', the function is request to + do a combined sign and encrypt. This currently only work with + GnuPG. + + - Command: pgg-decrypt-region start end + Decrypt the current region between START and END. If decryption + is successful, it replaces the current region contents (in the + accessible portion) with the resulting data. + + - Command: pgg-sign-region start end &optional cleartext + Make the signature from text between START and END. If the + optional third argument CLEARTEXT is non-`nil', or the function is + called interactively, it does not create a detached signature. In + such a case, it replaces the current region contents (in the + accessible portion) with the resulting data. + + - Command: pgg-verify-region start end &optional signature fetch + Verify the current region between START and END. If the optional + third argument SIGNATURE is non-`nil', or the function is called + interactively, it is treated as the detached signature of the + current region. + + If the optional 4th argument FETCH is non-`nil', or the function + is called interactively, we attempt to fetch the signer's public + key from the key server. + + - Command: pgg-insert-key + Retrieve the user's public key and insert it as ASCII-armored + format. + + - Command: pgg-snarf-keys-region start end + Collect public keys in the current region between START and END, + and add them into the user's keyring. + + +File: pgg.info, Node: Selecting an implementation, Next: Caching passphrase, Prev: User Commands, Up: How to use + +Selecting an implementation +=========================== + +Since PGP has a long history and there are a number of PGP +implementations available today, the function which each one has differs +considerably. For example, if you are using GnuPG, you know you can +select cipher algorithm from 3DES, CAST5, BLOWFISH, and so on, but on +the other hand the version 2 of PGP only supports IDEA. + + By default, if the variable `pgg-scheme' is not set, PGG searches the +registered scheme for an implementation of the requested service +associated with the named algorithm. If there are no match, PGG uses +`pgg-default-scheme'. In other words, there are two options to control +which command is used to process the incoming PGP armors. One is for +encrypting and signing, the other is for decrypting and verifying. + + - Variable: pgg-scheme + Force specify the scheme of PGP implementation for decrypting and + verifying. The value can be `gpg', `pgp', and `pgp5'. + + - Variable: pgg-default-scheme + Force specify the scheme of PGP implementation for encrypting and + signing. The value can be `gpg', `pgp', and `pgp5'. + + +File: pgg.info, Node: Caching passphrase, Next: Default user identity, Prev: Selecting an implementation, Up: How to use + +Caching passphrase +================== + +PGG uses a simple passphrase caching mechanism, which is enabled by +default. + + - Variable: pgg-cache-passphrase + If non-`nil', store passphrases. The default value of this + variable is `t'. If you were worry about security issue, however, + you could stop caching with setting it `nil'. + + - Variable: pgg-passphrase-cache-expiry + Elapsed time for expiration in seconds. + + +File: pgg.info, Node: Default user identity, Prev: Caching passphrase, Up: How to use + +Default user identity +===================== + +The PGP implementation is usually able to select the proper key to use +for signing and decryption, but if you have more than one key, you may +need to specify the key id to use. + + - Variable: pgg-default-user-id + User ID of your default identity. It defaults to the value + returned by `(user-login-name)'. You can customize this variable. + + - Variable: pgg-gpg-user-id + User ID of the GnuPG default identity. It defaults to `nil'. + This overrides `pgg-default-user-id'. You can customize this + variable. + + - Variable: pgg-pgp-user-id + User ID of the PGP 2.x/6.x default identity. It defaults to + `nil'. This overrides `pgg-default-user-id'. You can customize + this variable. + + - Variable: pgg-pgp5-user-id + User ID of the PGP 5.x default identity. It defaults to `nil'. + This overrides `pgg-default-user-id'. You can customize this + variable. + + +File: pgg.info, Node: Architecture, Next: Parsing OpenPGP packets, Prev: How to use, Up: Top + +Architecture +************ + +PGG introduces the notion of a "scheme of PGP implementation" (used +interchangeably with "scheme" in this document). This term refers to a +singleton object wrapped with the luna object system. + + Since PGG was designed for accessing and developing PGP +functionality, the architecture had to be designed not just for +interoperability but also for extensiblity. In this chapter we explore +the architecture while finding out how to write the PGG backend. + +* Menu: + +* Initializing:: +* Backend methods:: +* Getting output:: + + +File: pgg.info, Node: Initializing, Next: Backend methods, Up: Architecture + +Initializing +============ + +A scheme must be initialized before it is used. It had better +guarantee to keep only one instance of a scheme. + + The following code is snipped out of `pgg-gpg.el'. Once an instance +of `pgg-gpg' scheme is initialized, it's stored to the variable +`pgg-scheme-gpg-instance' and will be reused from now on. + + (defvar pgg-scheme-gpg-instance nil) + + (defun pgg-make-scheme-gpg () + (or pgg-scheme-gpg-instance + (setq pgg-scheme-gpg-instance + (luna-make-entity 'pgg-scheme-gpg)))) + + The name of the function must follow the +regulation--`pgg-make-scheme-' follows the backend name. + + +File: pgg.info, Node: Backend methods, Next: Getting output, Prev: Initializing, Up: Architecture + +Backend methods +=============== + +In each backend, these methods must be present. The output of these +methods is stored in special buffers (*Note Getting output::), so that +these methods must tell the status of the execution. + + - Method: pgg-scheme-lookup-key scheme string &optional type + Return keys associated with STRING. If the optional third + argument TYPE is non-`nil', it searches from the secret keyrings. + + - Method: pgg-scheme-encrypt-region scheme start end recipients + &optional sign + Encrypt the current region between START and END for RECIPIENTS. + If SIGN is non-`nil', do a combined sign and encrypt. If + encryption is successful, it returns `t', otherwise `nil'. + + - Method: pgg-scheme-decrypt-region scheme start end + Decrypt the current region between START and END. If decryption + is successful, it returns `t', otherwise `nil'. + + - Method: pgg-scheme-sign-region scheme start end &optional cleartext + Make the signature from text between START and END. If the + optional third argument CLEARTEXT is non-`nil', it does not create + a detached signature. If signing is successful, it returns `t', + otherwise `nil'. + + - Method: pgg-scheme-verify-region scheme start end &optional signature + Verify the current region between START and END. If the optional + third argument SIGNATURE is non-`nil', it is treated as the + detached signature of the current region. If the signature is + successfully verified, it returns `t', otherwise `nil'. + + - Method: pgg-scheme-insert-key scheme + Retrieve the user's public key and insert it as ASCII-armored + format. On success, it returns `t', otherwise `nil'. + + - Method: pgg-scheme-snarf-keys-region scheme start end + Collect public keys in the current region between START and END, + and add them into the user's keyring. On success, it returns `t', + otherwise `nil'. + + +File: pgg.info, Node: Getting output, Prev: Backend methods, Up: Architecture + +Getting output +============== + +The output of the backend methods (*Note Backend methods::) is stored in +special buffers, so that these methods must tell the status of the +execution. + + - Variable: pgg-errors-buffer + The standard error output of the execution of the PGP command is + stored here. + + - Variable: pgg-output-buffer + The standard output of the execution of the PGP command is stored + here. + + - Variable: pgg-status-buffer + The rest of status information of the execution of the PGP command + is stored here. + + +File: pgg.info, Node: Parsing OpenPGP packets, Next: Function Index, Prev: Architecture, Up: Top + +Parsing OpenPGP packets +*********************** + +The format of OpenPGP messages is maintained in order to publish all +necessary information needed to develop interoperable applications. +The standard is documented in RFC 2440. + + PGG has its own parser for the OpenPGP packets. + + - Function: pgg-parse-armor string + List the sequence of packets in STRING. + + - Function: pgg-parse-armor-region start end + List the sequence of packets in the current region between START + and END. + + - Variable: pgg-ignore-packet-checksum + If non-`nil', don't check the checksum of the packets. + + +File: pgg.info, Node: Function Index, Next: Variable Index, Prev: Parsing OpenPGP packets, Up: Top + +Function Index +************** + +* Menu: + +* pgg-decrypt-region: User Commands. +* pgg-encrypt-region: User Commands. +* pgg-insert-key: User Commands. +* pgg-parse-armor: Parsing OpenPGP packets. +* pgg-parse-armor-region: Parsing OpenPGP packets. +* pgg-scheme-decrypt-region: Backend methods. +* pgg-scheme-encrypt-region: Backend methods. +* pgg-scheme-insert-key: Backend methods. +* pgg-scheme-lookup-key: Backend methods. +* pgg-scheme-sign-region: Backend methods. +* pgg-scheme-snarf-keys-region: Backend methods. +* pgg-scheme-verify-region: Backend methods. +* pgg-sign-region: User Commands. +* pgg-snarf-keys-region: User Commands. +* pgg-verify-region: User Commands. + + +File: pgg.info, Node: Variable Index, Prev: Function Index, Up: Top + +Variable Index +************** + +* Menu: + +* pgg-cache-passphrase: Caching passphrase. +* pgg-default-scheme: Selecting an implementation. +* pgg-default-user-id: Default user identity. +* pgg-errors-buffer: Getting output. +* pgg-gpg-user-id: Default user identity. +* pgg-ignore-packet-checksum: Parsing OpenPGP packets. +* pgg-output-buffer: Getting output. +* pgg-passphrase-cache-expiry: Caching passphrase. +* pgg-pgp-user-id: Default user identity. +* pgg-pgp5-user-id: Default user identity. +* pgg-scheme: Selecting an implementation. +* pgg-status-buffer: Getting output. + + + +Tag Table: +Node: Top730 +Node: Overview1274 +Node: Prerequisites1760 +Node: How to use2320 +Node: User Commands3408 +Node: Selecting an implementation5817 +Node: Caching passphrase7058 +Node: Default user identity7613 +Node: Architecture8646 +Node: Initializing9295 +Node: Backend methods10022 +Node: Getting output12047 +Node: Parsing OpenPGP packets12673 +Node: Function Index13370 +Node: Variable Index14391 + +End Tag Table diff --git a/xemacs-packages/info/prog-modes.info b/xemacs-packages/info/prog-modes.info new file mode 100644 index 00000000..ba5d93ed --- /dev/null +++ b/xemacs-packages/info/prog-modes.info @@ -0,0 +1,2718 @@ +This is prog-modes.info, produced by makeinfo version 4.7 from +prog-modes.texi. + +INFO-DIR-SECTION XEmacs Editor +START-INFO-DIR-ENTRY +* Programming Modes: (prog-modes). Programming Modes for XEmacs. +END-INFO-DIR-ENTRY + + +File: prog-modes.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) + +1 The Programming Modes Package +******************************* + +This Info file contains the manual for the Programming Modes package. + +The node name for each entry in the menu is the name of the elisp file +containing the code that implements the functionality described. It is +highly recommended that you briefly peruse the elisp source code since +it can provide valuable information on usage and technique. This can +easily be done by typing `C-x 4 l RET' where is +the name of the elisp file to be loaded. + + In many cases, the `customize' command can be used to customize a +package's options. For those packages that support `customize', the +appropriate command is given. Otherwise, peruse the code as described +above to learn how to set the package's options. + + When you have entered a mode, you may get more info on the +capabilities of that mode by pressing `C-h m'. You may also get online +help describing functions provided by the mode by pressing `C-h f +'. + +* Menu: + +* Copying:: + +* asm-mode:: Editing Assembler Code +* autoconf-mode:: Editing Autoconf Input Files +* awk-mode:: Editing AWK Code +* cl-indent:: Enhanced Lisp-Indent Mode +* cvs:: Light CVS Support +* diff-mode:: Viewing and Editing Context Diffs +* eiffel:: Editing Eiffel Code +* icon:: Editing Icon Code +* javascript-mode:: Editing JavaScript Code +* ksh-mode:: Editing Shell Script (sh, ksh, bash) Code +* lua-mode:: Editing Lua Code +* m4-mode:: Editing m4 Code +* make-mode:: Editing Makefiles +* mode-compile:: Compiling Files According to Major-Mode +* modula2:: Editing Modula-2 Code +* old-c-mode:: Editing C Code +* p4:: Integration with Perforce Version Control +* pascal:: Editing Pascal Code +* php-mode:: Editing PHP Code +* postscript:: Editing PostScript Programs +* prolog:: Editing and Running Prolog Code +* rexx-mode:: Editing REXX Code +* rpm-spec-mode:: Editing RPM Spec Files +* simula:: Editing SIMULA 87 Code +* sql:: Specialized Mode for SQL Interpreters +* tcl:: Editing Tcl Code +* teco:: Teco Interpreter +* uil-mode:: Editing Motif UIL Code +* verilog-mode:: Editing Verilog HDL Source +* vrml-mode:: Editing VRML (.wrl) Files + +* XEmacs License:: XEmacs License + + +File: prog-modes.info, Node: Copying, Next: asm-mode, Prev: Top, Up: Top + +2 Copying +********* + +This document may be redistributed, verbatim or in modified form, under +the terms of the GNU General Public License, version 2 or any later +version. The same terms apply to the libraries it documents. A copy +of the General Public License is provided as an Appendix. + + Most XEmacs documentation has its own license, which is an ancestor +of the GNU Free Documentation License ("FDL"), and whose terms are +quite similar to those imposed by GNU on Emacs documentation. Why is +this manual licensed differently (under the GNU General Public License, +or "GPL"), and why does it have to be distributed separately from the +XEmacs User's Guide and the XEmacs Lisp Reference Manual? + + Taking the second question first, XEmacs is "community-owned" +software. That is, unlike GNU Emacs, there is no monopoly copyright +holder. Many of us, including the original Lucid authors, have +contributed our copyrights to the Free Software Foundation (FSF), and of +course much content is derived from GNU Emacs, and therefore is held by +the FSF. Another large chunk is held by Sun Microsystems, and a few +individual authors hold copyright to thousands of lines each. But many +individuals hold copyright to only a few dozen lines. Like the Linux +kernel, copyright ownership is distributed throughout a community. + + However, its license is "copyleft," _i.e._, it _requires_ that you +redistribute it under terms _identical_ to those under which you +received it, unless you have explicit permission of the copyright +holder. Because of the multiple owners, determining the ownership of +any given part of XEmacs is tedious, and perhaps impossible. For +practical purposes, then, the license of any substantial chunk of +existing XEmacs content cannot be changed, except to a later version of +the GPL, for those parts under GPL. (That is due to the _explicit_ +permission to change to a later version of the GPL, present in every +file of XEmacs.) + + Unfortunately, this severe restriction means that the GPL, FDL, and +the XEmacs documentation license ("XDL") are _mutually incompatible_. +That is, content licensed under any of the GPL, FDL, or XDL _may not_ +be mixed with content licensed under either of the other two without +changing the license of some of the content. But this requires +permission of the copyright holder, which is often difficult or +impossible to get. + + For example, you _may not_ take comments or docstrings from XEmacs +code and add them to the Lispref to mend a gap in the latter's coverage. +You _may not_ copy text from the Lispref into docstrings in the code. +And you _may not_ copy text from the GNU Emacs Lisp Reference to the +XEmacs Lisp Reference Manual. (In this case it is at least trivial to +ask permission, although it is rather unclear whether it would be +granted.) + + In fact, parts of this document were derived by copying from XEmacs +code under the GPL, without any further permission from the authors. +Thus, this document must be distributed under the GPL, as a "volume" +separate from the XEmacs documentation under the XDL. Note that the +"mere aggregation" clauses allow us to distribute in the same tarball. +But incorporating it as a node in the Lispref is prohibited, even if +done by inclusion. + + A bit of advocacy: + + If you look carefully at the additional restrictions imposed by the +soi-disant "free" documentation licenses, you discover that they are +simply proprietary restrictions guaranteeing a certain amount of +_unpaid_ political advertising to the Free Software Foundation and GNU +Project (and in the case of the FDL, this is extended to commercial +advertising by authors of original or derived works). Whether this is +"ethically justified" or not is a difficult question. What is certain +is that there is little social benefit to these terms (since the license +documents themselves contain the advocacy and must be included with any +distribution). + + I conclude it makes sense for XEmacs to reduce its restrictions, +where possible, to the "least common denominator," the GNU General +Public License. + + +File: prog-modes.info, Node: asm-mode, Next: autoconf-mode, Prev: Copying, Up: Top + +3 Editing Assembler Code +************************ + +This mode is used for editing Assembler code. The mode is automatically +invoked for buffers visiting any file ending with one of the following +extensions: `.s', `.S', `.asm'. + + The mode is based on text-mode. It defines a private abbrev table +that can be used to save abbrevs for assembler mnemonics. It binds +just five keys: + +`TAB' + Tab to next tab stop + +`:' + Outdent preceding label, tab to tab stop + +`comment char' + Place or move comment. `asm-comment-char' specifies which + character this is; you can use a different character in different + Asm mode buffers. Alternatively, you may set this variable in + `asm-mode-set-comment-hook', which is called near the beginning of + mode initialization. + +`C-j, C-m' + Newline and tab to tab stop + + + Code is automatically indented to the first tab stop level. + + Turning on Asm mode runs the hook `asm-mode-hook' at the end of +initialization. + + To configure this package, type: + + M-x customize-group RET asm RET + + +File: prog-modes.info, Node: autoconf-mode, Next: awk-mode, Prev: asm-mode, Up: Top + +4 Editing Autoconf Input Files +****************************** + +This mode is used for editing autoconf input files. It is automatically +invoked for buffers visiting the following types of files: + + * any file ending with an extension of `.m4' + + * any file named `configure' ending with an extension of either + `.in' or `.ac'. + + + To configure this package please view the source code. This can be +done by typing `C-x 4 l autoconf-mode'. + +* Menu: + +* About Autoconf: about-autoconf. + + +File: prog-modes.info, Node: about-autoconf, Prev: autoconf-mode, Up: autoconf-mode + +4.1 About Autoconf +================== + +Autoconf is an extensible package of m4 macros that produce shell +scripts to automatically configure software source code packages. These +scripts can adapt the packages to many kinds of UNIX-like systems +without manual user intervention. Autoconf creates a configuration +script for a package from a template file that lists the operating +system features that the package can use, in the form of m4 macro calls. + + +File: prog-modes.info, Node: awk-mode, Next: cl-indent, Prev: autoconf-mode, Up: Top + +5 Editing AWK Code +****************** + +This mode is used for editing Awk code. It is automatically invoked for +buffers visiting the following types of files: + + * any file ending with an extension of `.awk'. + + * any file that has an interpretor line (the "shebang" line) + specifying "awk". + + + The mode operates much like C mode except for the syntax of +comments. It uses the same keymap as C mode and has the same variables +for customizing indentation. It has its own abbrev table and its own +syntax table. + + Turning on AWK mode calls the value of the variable `awk-mode-hook' +with no arguments, if that value is non-nil. + + NOTE: This library is obsolete. Support for AWK is now available +directly via the cc-mode package. *Note AWK Mode: (cc-mode)AWK Mode., +for details. + +* Menu: + +* About Awk: about-awk. + + +File: prog-modes.info, Node: about-awk, Prev: awk-mode, Up: awk-mode + +5.1 About Awk +============= + +Awk is a text-processing programming language. It is a useful and +simple tool for manipulating text. + + +File: prog-modes.info, Node: cl-indent, Next: cvs, Prev: awk-mode, Up: Top + +6 Enhanced Lisp-Indent Mode +*************************** + +This package provides an extension to lisp-mode. It supplies a single +entry point, `common-lisp-indent-function', which performs indentation +in the preferred style for Common Lisp code. To enable it add the +following to your `user-init-file': + + (setq lisp-indent-function 'common-lisp-indent-function) + + To configure this package, type: + + M-x customize-group RET lisp-indent RET + + +File: prog-modes.info, Node: cvs, Next: diff-mode, Prev: cl-indent, Up: Top + +7 Light CVS Support +******************* + +This package provides simple CVS support within the editing session. + + The package provides the following features: + + * Displays the CVS revision in the mode line. + + * Compares file changes between CVS revisions using `ediff'. + + * Keystrokes and menu entries to execute `cvs status', `cvs log' and + `cvsann'. + + * Simple interface to `cvs commit' and `cvs update' commands. + + * Status listing per directory. + + * `msb' support (better buffer selection). + + * `dired' support. + + * Softlink tree support. + + * Little module support (status and update). + + + To install this library, add the following to your `user-init-file': + + (require 'cvs) + + To configure this package please view the source code. This can be +done by typing `C-x 4 l cvs'. + + For related packages please see *Note PCL-CVS: (pcl-cvs)Top. and +*Note Version Control: (xemacs)Version Control. + +* Menu: + +* About CVS: about-cvs. + + +File: prog-modes.info, Node: about-cvs, Prev: cvs, Up: cvs + +7.1 About CVS +============= + +CVS is the Concurrent Versions System, an open-source +network-transparent version control system. More information on CVS +can be found at CVS Home (http://www.cvshome.org/). + + +File: prog-modes.info, Node: diff-mode, Next: eiffel, Prev: cvs, Up: Top + +8 Viewing and Editing Context Diffs +*********************************** + +This mode facilitates viewing and editing of context diffs. It is +automatically invoked buffers visiting any file ending with one of the +following extensions: `.diff', `.diffs', `.patch', `.rej'. + + The mode provides support for font-lock, outline, navigation +commands, editing and various conversions as well as jumping. + + The following key mappings are defined: + +`C-c' << Prefix Command >> +`M-A' diff-ediff-patch +`M-C' diff-unified->context +`M-K' diff-file-kill +`M-N' diff-file-next +`M-P' diff-file-prev +`M-R' diff-reverse-direction +`M-U' diff-context->unified +`M-W' widen +`M-k' diff-hunk-kill +`M-n' diff-hunk-next +`M-o' diff-goto-source +`M-p' diff-hunk-prev +`M-r' diff-restrict-view +`M-{' diff-file-prev +`M-}' diff-file-next +`M-delete' scroll-down +`M-return' diff-goto-source +`M-space' scroll-up +`M-C-m' diff-goto-source +`C-c C-a' diff-apply-hunk +`C-c C-c' diff-goto-source +`C-c C-s' diff-split-hunk +`C-c C-t' diff-test-hunk + + To configure this package, type: + + M-x customize-group RET diff-mode RET + + +File: prog-modes.info, Node: eiffel, Next: icon, Prev: diff-mode, Up: Top + +9 Editing Eiffel Code +********************* + +This mode is used for editing Eiffel code. It is automatically invoked +for buffers visiting any file ending in an extension of `.e'. + + The following key mappings are defined: + +`return' reindent-then-newline-and-indent +`C-c' << Prefix Command >> +`C-j' newline-and-indent +`C-x' << Prefix Command >> +`M-'' eif-feature-quote +`M-q' eif-fill-paragraph +`M-C-a' eif-beginning-of-feature +`M-C-e' eif-end-of-feature +`M-C-q' eif-indent-construct +`C-c C-c' eif-compile +`C-c C-o' eif-set-compile-options +`C-c C-r' eif-run +`C-c C-s' eif-short +`C-x n' << Prefix Command >> +`C-x n d' eif-narrow-to-feature + + To configure this package, type: + + M-x customize-group RET eiffel RET + +* Menu: + +* About Eiffel: about-eiffel. + + +File: prog-modes.info, Node: about-eiffel, Prev: eiffel, Up: eiffel + +9.1 About Eiffel +================ + +The Eiffel programming language was created by Bertrand Meyer and +developed by his company, Interactive Software Engineering (ISE) of +Goleta, CA in 1985. More information on Eiffel can be found at the +Eiffel Web Site +(http://www.engin.umd.umich.edu/CIS/course.des/cis400/eiffel/eiffel.html). + + +File: prog-modes.info, Node: icon, Next: javascript-mode, Prev: eiffel, Up: Top + +10 Editing Icon Code +******************** + +This mode is used for editing Icon code. It is automatically invoked +for buffers visiting any file ending in an extension of `.icn'. + + The mode provides the following features: + + * Expression and list commands understand all Icon brackets. + + * Tab indents for Icon code. + + * Paragraphs are separated by blank lines only. + + * Delete converts tabs to spaces as it moves back. + + The following key mappings are defined: + +`{' electric-icon-brace +`}' electric-icon-brace +`delete' backward-delete-char-untabify +`menu-bar' << Prefix command "Icon" >> +`M-backspace' mark-icon-function +`M-C-a' beginning-of-icon-defun +`M-C-e' end-of-icon-defun +`M-C-h' mark-icon-function +`M-C-q' indent-icon-exp + + The variables controlling indentation style are: + +`icon-tab-always-indent' + Non-nil means TAB in Icon mode should always reindent the current + line, regardless of where in the line point is when the TAB + command is used. + +`icon-auto-newline' + Non-nil means automatically newline before and after braces + inserted in Icon code. + +`icon-indent-level' + Indentation of Icon statements within surrounding block. The + surrounding block's indentation is the indentation of the line on + which the open-brace appears. + +`icon-continued-statement-offset' + Extra indentation given to a substatement, such as the then-clause + of an if or body of a while. + +`icon-continued-brace-offset' + Extra indentation given to a brace that starts a substatement. + This is in addition to `icon-continued-statement-offset'. + +`icon-brace-offset' + Extra indentation for line if it starts with an open brace. + +`icon-brace-imaginary-offset' + An open brace following other text is treated as if it were this + far to the right of the start of its line. + + + Turning on Icon mode calls the value of the variable `icon-mode-hook' +with no args, if that value is non-nil. + + To configure this package, type: + + M-x customize-group RET icon RET + +* Menu: + +* About Icon: about-icon. + + +File: prog-modes.info, Node: about-icon, Prev: icon, Up: icon + +10.1 About Icon +=============== + +Icon is a high-level, general-purpose programming language with a large +repertoire of features for processing data structures and character +strings. Icon is an imperative, procedural language with a syntax +reminiscent of C and Pascal, but with semantics at a much higher level. +More information on Icon can be found at The Icon Programming Language +(http://www.cs.arizona.edu/icon/). + + +File: prog-modes.info, Node: javascript-mode, Next: ksh-mode, Prev: icon, Up: Top + +11 Editing JavaScript Code +************************** + +This mode is used for editing JavaScript code. It is automatically +invoked for buffers visiting any file ending in an extension of `.js' or +`.pac'. + + See the documentation for `c++-mode': JavaScript mode is an +extension of it (*note CC Mode: (cc-mode)Top.). Use the hook +`javascript-mode-hook' to execute custom code when entering JavaScript +mode. + + The following key mappings are defined: + +`#' c-electric-pound +`(, )' c-electric-paren +`*' c-electric-star +`,' c-electric-semi&comma +`/' c-electric-slash +`:' c-electric-colon +`;' c-electric-semi&comma +`<' c-electric-lt-gt +`>' c-electric-lt-gt +`{' c-electric-brace +`}' c-electric-brace +`backspace' c-electric-backspace +`delete' c-electric-delete +`return' c-context-line-break +`tab' c-indent-command +`C-c' << Prefix Command >> +`C-i' c-indent-command +`C-m' c-context-line-break +`C-x' << Prefix Command >> +`M-a' c-beginning-of-statement +`M-c' c-comment-edit-at-point +`M-e' c-end-of-statement +`M-j' c-indent-new-comment-line +`M-q' c-fill-paragraph +`M-backspace' backward-kill-word +`M-backward' backward-kill-word +`M-delete' backward-kill-word +`M-linefeed' c-indent-new-comment-line +`M-C-h' backward-kill-word +`M-C-j' c-indent-new-comment-line +`M-C-q' c-indent-exp +`M-C-kp-left' c-beginning-of-statement +`M-C-kp-right' c-end-of-statement +`M-C-left' c-beginning-of-statement +`M-C-right' c-end-of-statement +`C-c .' c-set-style +`C-c C-\' c-backslash-region +`C-c C-a' c-toggle-auto-state +`C-c C-b' c-submit-bug-report +`C-c C-c' comment-region +`C-c C-d' c-toggle-hungry-state +`C-c C-n' c-forward-conditional +`C-c C-o' c-set-offset +`C-c C-p' c-backward-conditional +`C-c C-q' c-indent-defun +`C-c C-s' c-show-syntactic-information +`C-c C-t' c-toggle-auto-hungry-state +`C-c C-u' c-up-conditional +`C-x f' c-fill-paragraph + + To configure this package, type: + + M-x customize-group RET javascript RET + +* Menu: + +* About JavaScript: about-javascript. + + +File: prog-modes.info, Node: about-javascript, Prev: javascript-mode, Up: javascript-mode + +11.1 About JavaScript +===================== + +JavaScript is a compact, object-based scripting language for developing +client and server Internet applications. + + +File: prog-modes.info, Node: ksh-mode, Next: lua-mode, Prev: javascript-mode, Up: Top + +12 Editing Shell Script (sh, ksh, bash) Code +******************************************** + +This mode is used for editing shell scripts written for the Bourne +(sh), Korn (ksh) or Bourne Again (bash) shells. It is NOT +automatically invoked for any particular file extension. To invoke +this mode while editing a file, type `M-x ksh-mode'. + + The following key mappings are defined: + +`linefeed' reindent-then-newline-and-indent +`tab' ksh-indent-line +`C-c' << Prefix Command >> +`C-i' ksh-indent-line +`C-j' reindent-then-newline-and-indent +`M-tab' ksh-complete-symbol +`M-C-i' ksh-complete-symbol +`C-c tab' ksh-completion-init-and-pickup +`C-c C-i' ksh-completion-init-and-pickup + + The variables controlling indentation style are: + +`ksh-indent' + Indentation of ksh statements with respect to containing block. + Default value is 2. + +`ksh-case-indent' + Additional indentation for statements under case items. Default + value is nil which will align the statements one position past the + ")" of the pattern. + +`ksh-case-item-offset' + Additional indentation for case items within a case statement. + Default value is 2. + +`ksh-group-offset' + Additional indentation for keywords "do" and "then". Default + value is -2. + +`ksh-brace-offset' + Additional indentation of "{" under functions or brace groupings. + Default value is 0. + +`ksh-multiline-offset' + Additional indentation of line that is preceded of a line ending + with a `\' to make it continue on next line. + +`ksh-tab-always-indent' + Controls the operation of the `TAB' key. If t (the default), always + reindent the current line. If nil, indent the current line only if + point is at the left margin or in the line's indentation; otherwise + insert a tab. + +`ksh-match-and-tell' + If non-nil echo in the minibuffer the matching compound command + for the "done", "}", "fi", or "esac". Default value is t. + +`ksh-align-to-keyword' + Controls whether nested constructs align from the keyword or the + current indentation. If non-nil, indentation will be relative to + the column the keyword starts. If nil, indentation will be + relative to the current indentation of the line the keyword is on. + The default value is non-nil. + +`ksh-comment-regexp' + Regular expression used to recognize comments. Customize to support + ksh-like languages. Default value is "\s *#". + + + An example of how to set up this mode is as follows: + + (setq ksh-mode-hook + (function (lambda () + (font-lock-mode 1) ;; font-lock the buffer + (setq ksh-indent 8) + (setq ksh-group-offset -8) + (setq ksh-brace-offset -8) + (setq ksh-tab-always-indent t) + (setq ksh-match-and-tell t) + (setq ksh-align-to-keyword t) ;; Turn on keyword alignment + ))) + + To configure this package please view the source code. This can be +done by typing `C-x 4 l ksh-mode'. + + For a related package, see `sh-script'. + + +File: prog-modes.info, Node: lua-mode, Next: m4-mode, Prev: ksh-mode, Up: Top + +13 Editing Lua Code +******************* + +This mode is used for editing Lua code. It is automatically invoked for +buffers visiting any file ending in the extension `.lua'. + + To configure this mode, type: + + M-x customize-group RET lua RET + +* Menu: + +* About Lua: about-lua. + + +File: prog-modes.info, Node: about-lua, Prev: lua-mode, Up: lua-mode + +13.1 About Lua +============== + +Lua is a powerful light-weight programming language designed for +extending applications. Lua is also frequently used as a +general-purpose, stand-alone language. More information on Lua can be +found at The Programming Language Lua (http://www.lua.org/). + + +File: prog-modes.info, Node: m4-mode, Next: make-mode, Prev: lua-mode, Up: Top + +14 Editing m4 Code +****************** + +This mode is used for editing m4 macro definitions. It is NOT +automatically invoked for any particular file extension. To invoke +this mode while editing a file, type `M-x m4-mode'. + + The mode has most of the syntax right (i.e., sexp motion commands +work, but function motion commands don't). It also sets up font-lock +for colorization. + + To configure this package please view the source code. This can be +done by typing `C-x 4 l m4-mode'. + + NOTE: The preferred package for editing m4 code is autoconf mode. +*Note autoconf-mode::., for details. + +* Menu: + +* About m4: about-m4. + + +File: prog-modes.info, Node: about-m4, Prev: m4-mode, Up: m4-mode + +14.1 About m4 +============= + +m4 is a general purpose macro processor that can be used to preprocess +C and assembly language programs, among other things. Besides the +straightforward replacement of one string of text by another, m4 lets +you perform: + + * integer arithmetic + + * file inclusion + + * conditional macro expansion + + * string and substring manipulation + + + +File: prog-modes.info, Node: make-mode, Next: mode-compile, Prev: m4-mode, Up: Top + +15 Editing Makefiles +******************** + +This mode is used for editing Makefiles. It is automatically invoked +for for buffers visiting the following types of files: + + * any file ending with an extension of `.ma?ke?' or `.am' + + * any file named `GNU[Mm]akefile' or `[Mm]akefile' with an extension + of `.in'. + + * any file that has an interpretor line (the "shebang" line) + specifying "make". + + + The mode knows about Makefile syntax and defines `M-n' and `M-p' to +move to next and previous productions. + + The keys `$', `=', `:' and `.' are electric; they try to help you +fill in a macro reference, macro definition, ordinary target name, or +special target name, respectively. Such names are completed using a +list of targets and macro names parsed out of the makefile. This list +is automatically updated, if necessary, whenever you invoke one of these +commands. You can force it to be updated with `C-c C-p'. + + The command `C-c C-f' adds certain filenames in the current +directory as targets. You can filter out filenames by setting the +variable `makefile-ignored-files-in-pickup-regex'. + + The command `C-c C-u' grinds for a bit, then pops up a report buffer +showing which target names are up-to-date with respect to their +prerequisites, which targets are out-of-date, and which have no +prerequisites. + + The command `C-c C-b' pops up a browser window listing all target and +macro names. You can mark or unmark items wit `C-c SPC', and insert all +marked items back in the Makefile with `C-c TAB'. + + The command `C-c TAB' in the makefile buffer inserts a GNU make +builtin. You will be prompted for the builtin's args. + + The following key mappings are defined: + +`C-c' << Prefix Command >> +`M-n' makefile-next-dependency +`M-p' makefile-previous-dependency +`M-tab' makefile-complete +`M-C-i' makefile-complete +`C-c :' makefile-insert-target-ref +`C-c tab' makefile-insert-gmake-function +`C-c C-\' makefile-backslash-region +`C-c C-b' makefile-switch-to-browser +`C-c C-c' comment-region +`C-c C-f' makefile-pickup-filenames-as-targets +`C-c C-i' makefile-insert-gmake-function +`C-c C-p' makefile-pickup-everything +`C-c C-u' makefile-create-up-to-date-overview + + In the browser, use the following keys: + +`I' makefile-browser-insert-selection-and-quit +`i' makefile-browser-insert-selection +`n' makefile-browser-next-line +`p' makefile-browser-previous-line +`q' makefile-browser-quit +`space' makefile-browser-toggle +`C-c' << Prefix Command >> +`C-n' makefile-browser-next-line +`C-p' makefile-browser-previous-line +`C-c return' makefile-browser-insert-continuation +`C-c C-m' makefile-browser-insert-continuation + + Makefile mode can be configured by modifying the following variables: + +`makefile-browser-buffer-name:' + Name of the macro- and target browser buffer. + +`makefile-target-colon:' + The string that gets appended to all target names inserted by + `makefile-insert-target'. ":" or "::" are quite common values. + +`makefile-macro-assign:' + The string that gets appended to all macro names inserted by + `makefile-insert-macro'. The normal value should be " = ", since + this is what standard make expects. However, newer makes such as + dmake allow a larger variety of different macro assignments, so you + might prefer to use " += " or " := " . + +`makefile-tab-after-target-colon:' + If you want a `TAB' (instead of a space) to be appended after the + target colon, then set this to a non-nil value. + +`makefile-browser-leftmost-column:' + Number of blanks to the left of the browser selection mark. + +`makefile-browser-cursor-column:' + Column in which the cursor is positioned when it moves up or down + in the browser. + +`makefile-browser-selected-mark:' + String used to mark selected entries in the browser. + +`makefile-browser-unselected-mark:' + String used to mark unselected entries in the browser. + +`makefile-browser-auto-advance-after-selection-p:' + If this variable is set to a non-nil value the cursor will + automagically advance to the next line after an item has been + selected in the browser. + +`makefile-pickup-everything-picks-up-filenames-p:' + If this variable is set to a non-nil value then + `makefile-pickup-everything' also picks up filenames as targets + (i.e. it calls `makefile-pickup-filenames-as-targets'), otherwise + filenames are omitted. + +`makefile-cleanup-continuations-p:' + If this variable is set to a non-nil value then Makefile mode will + assure that no line in the file ends with a backslash (the + continuation character) followed by any whitespace. This is done + by silently removing the trailing whitespace, leaving the + backslash itself intact. IMPORTANT: Please note that enabling + this option causes Makefile mode to MODIFY A FILE WITHOUT YOUR + CONFIRMATION when "it seems necessary". + +`makefile-browser-hook:' + A function or list of functions to be called just before the + browser is entered. This is executed in the makefile buffer. + +`makefile-special-targets-list:' + List of special targets. You will be offered to complete on one of + those in the minibuffer whenever you enter a `.'. at the + beginning of a line in Makefile mode. + + + To configure this package, type: + + M-x customize-group RET makefile RET + +* Menu: + +* About Make: about-make. + + +File: prog-modes.info, Node: about-make, Prev: make-mode, Up: make-mode + +15.1 About Make +=============== + +A Makefile is used by a `make' utility to automatically determine which +pieces of a large program need to be recompiled, and to issue the +commands to recompile them. *Note Make: (make)Top., for details. + + +File: prog-modes.info, Node: mode-compile, Next: modula2, Prev: make-mode, Up: Top + +16 Compiling Files According to Major-Mode +****************************************** + +The `compile' command is very rudimentary in its creation of its +compilation command, using "make -k" by default. This package provides +an intelligent replacement for the `compile' command. *Note +Compilation: (xemacs)Compilation., for details. + + The `mode-compile' command functions as a layer above `compile'. +Its purpose is mainly to build a smarter compile command for `compile' +to execute. This compile command is built according to number of +parameters: + + * the major-mode + + * presence or absence of a makefile in the current directory + + * the `buffer-file-name' and extension + + * contents of the current buffer (`main' function, "#!/path/shell", + ...) + + * and more ... (see below) + + + Most of these parameters are highly customizable through Emacs Lisp +variables (to be set in your `user-init-file' or through the +Customization menu). Running `mode-compile' after a universal-argument +(`C-u') allows remote compilations; the user is prompted for the host +name to execute the compilation command. The `mode-compile-kill' +function terminates a running compilation session launched by +`mode-compile'. + + By default, `mode-compile' is very verbose and waits a user-specified +number of seconds after displaying each message to give the user time +to read it. The variables `mode-compile-expert-p' and +`mode-compile-reading-time' can be used to change this behaviour. On +Windows-based systems, the variable `mode-compile-other-frame-p' will +create a new frame and launch the compilation command in it. + +* Menu: + +* compile-cust:: Customization +* compile-compilation-mode:: compilation-mode +* compile-makefile-mode:: makefile-mode +* compile-emacs-lisp-mode:: emacs-lisp-mode, lisp-interaction-mode +* compile-dired-mode:: dired-mode +* compile-sh-mode:: sh-mode, csh-mode, zsh-mode +* compile-c?perl-mode:: c?perl-mode +* compile-tcl-mode:: tcl-mode +* compile-c-mode:: c-mode, c++-mode +* compile-ada-mode:: ada-mode +* compile-fortran-mode:: fortran-mode +* compile-java-mode:: java-mode +* compile-python-mode:: python-mode +* compile-message-mode:: message-mode +* compile-catchall:: Miscellaneous Modes + + +File: prog-modes.info, Node: compile-cust, Next: compile-compilation-mode, Prev: mode-compile, Up: mode-compile + +16.1 Customization +================== + +This section explains how the `compile-command' is built according to +the `major-mode' and how to customize it. The major modes currently +supported are: + +ada-mode c++-mode c-mode +c?perl-mode compilation-mode csh-mode +dired-mode emacs-lisp-mode fortran-mode +fundamental-mode indented-text-mode java-mode +lisp-interaction-mode makefile-mode python-mode +sh-mode tcl-mode text-mode +zsh-mode + + For other modes a default behaviour is provided. + + When running `mode-compile' or `mode-compile-kill' the hooks +`mode-compile-(before|after)-(compile|kill)-hook' are executed. The +current buffer can be automatically saved if +`mode-compile-always-save-buffer-p' is set to `t'. All the modified +buffers can be automatically saved if `mode-compile-save-all-p' is set +to `t'. + + To configure this package, type: + + M-x customize-group RET compilation RET + + +File: prog-modes.info, Node: compile-compilation-mode, Next: compile-makefile-mode, Prev: compile-cust, Up: mode-compile + +16.2 compilation-mode +===================== + +Calls `compile' with the last compile command. + + +File: prog-modes.info, Node: compile-makefile-mode, Next: compile-emacs-lisp-mode, Prev: compile-compilation-mode, Up: mode-compile + +16.3 makefile-mode +================== + +The makefile is run with make through `compile' (user is prompted for +the rule to run, see variable `mode-compile-preferred-default-makerule' +to see how a default choice could be selected). + + +File: prog-modes.info, Node: compile-emacs-lisp-mode, Next: compile-dired-mode, Prev: compile-makefile-mode, Up: mode-compile + +16.4 emacs-lisp-mode, lisp-interaction-mode +=========================================== + +If the buffer is a `.el' file we `byte-compile' it to produce a `.elc' +file. Otherwise, just `byte-compile' the buffer (this does not use +`compile' but `byte-compile'). + + +File: prog-modes.info, Node: compile-dired-mode, Next: compile-sh-mode, Prev: compile-emacs-lisp-mode, Up: mode-compile + +16.5 dired-mode +=============== + +Find a `makefile' in the directory and run make with it (like in +`makefile-mode'), else try to `byte-recompile' all `.el' files older +than their associated `.elc' files (unlike `byte-recompile-directory' +this is not recursive), finally if no `.el' files are present ask +compilation command to user by calling `default-compile'. To find a +`makefile' a regexp is provided which name is +`mode-compile-makefile-regexp'. + + +File: prog-modes.info, Node: compile-sh-mode, Next: compile-c?perl-mode, Prev: compile-dired-mode, Up: mode-compile + +16.6 sh-mode, csh-mode, zsh-mode +================================ + +Run "[cz]?sh" with debugging arguments as specified in +`[cz]?sh-dbg-flags' on the currently edited file. + + +File: prog-modes.info, Node: compile-c?perl-mode, Next: compile-tcl-mode, Prev: compile-sh-mode, Up: mode-compile + +16.7 c?perl-mode +================ + +Run file with "perl -w" (can step through errors with compile's +`next-error' command). + + +File: prog-modes.info, Node: compile-tcl-mode, Next: compile-c-mode, Prev: compile-c?perl-mode, Up: mode-compile + +16.8 tcl-mode +============= + +Run file with "wish" (can step through errors with compile's +`next-error' command). + + +File: prog-modes.info, Node: compile-c-mode, Next: compile-ada-mode, Prev: compile-tcl-mode, Up: mode-compile + +16.9 c-mode, c++-mode +===================== + +First it tries to see if there is a `makefile' in the directory. +Makefiles to look for are specified by the variable +`mode-compile-makefile-regexp'. If yes two cases could happen: there is +only one makefile so use it, or there is more than one (sometimes when +you need to write portable soft you could have some makefiles by system: +SunOs.make, HP.make ...), in that case prompt to user for choice (with +smart completion). Once the makefile has been selected it extract the +rules from it and ask to user to choose a rule to make (with smart +completion, see variable `mode-compile-preferred-default-makerule' to +see how a default choice could be selected). + + There are some cases where no makefiles are present (YES I KNOW this +is bad practice but you sometimes have no need to write a Makefile). In +that case the function tries to build the most intelligent compilation +command by using the favourite user C/C++ compiler: value of +environment variable "CC" or "CXX" or first found, in the PATH, of +compilers specified in variable `cc-compilers-list' or +`c++-compilers-list'. Then it looks for the environment variable +"CFLAGS" of "CXXFLAGS" to append to the compiler command, finds the +file to compile: .(c|cc|C|cpp) (see *) +and asks for confirmation. If you really trust mode-compile will build +the correct command and want to bypass confirmation you could set the +variable `mode-compile-never-edit-command-p' to `t'. + + +File: prog-modes.info, Node: compile-ada-mode, Next: compile-fortran-mode, Prev: compile-c-mode, Up: mode-compile + +16.10 ada-mode +============== + +Same as c/c++-mode but run Ada compiler on the Ada file. There are no +companion file and no way to find a main function in Ada. + + +File: prog-modes.info, Node: compile-fortran-mode, Next: compile-java-mode, Prev: compile-ada-mode, Up: mode-compile + +16.11 fortran-mode +================== + +Same as c-mode but run Fortran compiler on .[Ff](or)? files. + + +File: prog-modes.info, Node: compile-java-mode, Next: compile-python-mode, Prev: compile-fortran-mode, Up: mode-compile + +16.12 java-mode +=============== + +Same as c-mode but call "javac" without the -o option on .java files + + +File: prog-modes.info, Node: compile-python-mode, Next: compile-message-mode, Prev: compile-java-mode, Up: mode-compile + +16.13 python-mode +================= + +Run file with "python" (can step through errors with compile's +`next-error' command). + + +File: prog-modes.info, Node: compile-message-mode, Next: compile-catchall, Prev: compile-python-mode, Up: mode-compile + +16.14 message-mode +================== + +Run `message-send'. + + +File: prog-modes.info, Node: compile-catchall, Prev: compile-message-mode, Up: mode-compile + +16.15 Miscellaneous Modes +========================= + +This handles `fundamental-mode', `text-mode', `indented-text-mode' and +any unknown modes. + + Try to guess what the file is by + + * Looking at its name and extension (see variable + `mode-compile-filename-regexp-alist'). + + * Looking at string "#!/path/shell" at first line to extract shell + to run the script with (see variable `mode-compile-shell-alist'). + + * Looking at a makefile in current directory. + + * Calling `compile' with the last compile command which is asked to + be edited by user + + + The `kill-compile' command is then bound dynamically (buffer-local). + + +File: prog-modes.info, Node: modula2, Next: old-c-mode, Prev: mode-compile, Up: Top + +17 Editing Modula-2 Code +************************ + +This mode is used for editing Modula-2 code. It is NOT automatically +invoked for any particular file extension. To invoke this mode while +editing a file, type `M-x modula-2-mode'. + + The mode provides convenient abbrevs for Modula-2 keywords, knows +about the standard layout rules, and supports a native compile command. + + All control constructs of Modula-2 can be reached by typing C-c +followed by the first character of the construct. + + The following key mappings are defined: + +C-c b begin C-c c case +C-c d definition C-c e else +C-c f for C-c h header +C-c i if C-c m module +C-c l loop C-c o or +C-c p procedure Control-c Control-w with +C-c r record C-c s stdio +C-c t type C-c u until +C-c v var C-c w while +C-c x export C-c y import +C-c { begin-comment C-c } end-comment +C-c C-z suspend Emacs C-c C-t toggle +C-c C-c compile M-x m2-next-error + next-error +C-c C-l link + + Following are some important variables: + +`m2-indent' + controls the number of spaces for each indentation. + +`m2-compile-command' + holds the command to compile a Modula-2 program. + +`m2-link-command' + holds the command to link a Modula-2 program. + + To configure this package, type: + + M-x customize-group RET modula2 RET + +* Menu: + +* About Modula-2: about-modula2. + + +File: prog-modes.info, Node: about-modula2, Prev: modula2, Up: modula2 + +17.1 About Modula-2 +=================== + +Modula-2 is a programming language developed by Niklaus Wirth at ETH in +Zurich, Switzerland in the late 70's. Wirth also developed Algol-W, +Pascal, Modula, and Oberon. + + Modula-2 corrects some of the deficiencies of Pascal. It is suitable +for learning programming, for large projects written and maintained in +the fashion of professional software engineers, and for real time +embedded systems. Modula-2 is small, expressive, easy to learn and to +read. + + +File: prog-modes.info, Node: old-c-mode, Next: p4, Prev: modula2, Up: Top + +18 Editing C Code +***************** + +This is a smart editing mode for C code. It knows a lot about C syntax +and tries to position the cursor according to C layout conventions. +You can change the details of the layout style with option variables. + + The mode provides the following features: + + * Expression and list commands understand all C brackets. + + * Tab indents for C code. + + * Comments are delimited with /* ... */. + + * Paragraphs are separated by blank lines only. + + * Delete converts tabs to spaces as it moves back. + + The variables controlling indentation style are: + +`c-tab-always-indent' + Non-nil means TAB in C mode should always reindent the current + line, regardless of where in the line point is when the TAB + command is used. + +`c-auto-newline' + Non-nil means automatically newline before and after braces, and + after colons and semicolons, inserted in C code. + +`c-indent-level' + Indentation of C statements within surrounding block. The + surrounding block's indentation is the indentation of the line on + which the open-brace appears. + +`c-continued-statement-offset' + Extra indentation given to a substatement, such as the then-clause + of an if or body of a while. + +`c-continued-brace-offset' + Extra indentation given to a brace that starts a substatement. + This is in addition to c-continued-statement-offset. + +`c-brace-offset' + Extra indentation for line if it starts with an open brace. + +`c-brace-imaginary-offset' + An open brace following other text is treated as if it were this + far to the right of the start of its line. + +`c-argdecl-indent' + Indentation level of declarations of C function arguments. + +`c-label-offset' + Extra indentation for line that is a label, or case or default. + + + NOTE: This package has been obsoleted by the cc-mode package (*note +CC Mode: (cc-mode)Top.). cc-mode can be quite slow, however, on large +files, even on fast machines. This version works with no problems on +the XEmacs source code and is very very fast. + + To configure this package, type: + + M-x customize-group RET old-c RET + + +File: prog-modes.info, Node: p4, Next: pascal, Prev: old-c-mode, Up: Top + +19 Integration with Perforce Version Control +******************************************** + +This package provides simple integration with Perforce Version Control. + + To use this package, add the following line to your `user-init-file': + + (load-library "p4") + + To configure this package, type: + + M-x customize-group RET p4 RET + +* Menu: + +* About Perforce: about-perforce. + + +File: prog-modes.info, Node: about-perforce, Prev: p4, Up: p4 + +19.1 About Perforce +=================== + +The Perforce SCM System features comprehensive software configuration +management capabilities built around a scalable client/server +architecture. Requiring only TCP/IP, developers can access the Perforce +Server through a variety of Perforce clients (Windows GUI, Web, or +Command-Line). Perforce can be deployed quickly and easily, and requires +minimal administration1, even for large or distributed sites. + + More information on Perforce can be found at +`http://www.perforce.com/'. + + +File: prog-modes.info, Node: pascal, Next: php-mode, Prev: p4, Up: Top + +20 Editing Pascal Code +********************** + +This mode is used for editing Pascal code. It is automatically invoked +for buffers visiting any file ending with an extension of `.pas'. + + The mode provides the following capabilities: + + * TAB indents for Pascal code. + + * Delete converts tabs to spaces as it moves back. + + * `pascal-complete-word' completes the word around current point + with respect \ to position in code + + * `pascal-show-completions' shows all possible completions at this + point. + + Other useful functions are: + +`pascal-mark-defun' + Mark function. + +`pascal-insert-block' + insert begin ... end; + +`pascal-star-comment' + insert (* ... *) + +`pascal-comment-area' + Put marked area in a comment, fixing nested comments. + +`pascal-uncomment-area' + Uncomment an area commented with `pascal-comment-area'. + +`pascal-beg-of-defun' + Move to beginning of current function. + +`pascal-end-of-defun' + Move to end of current function. + +`pascal-goto-defun' + Goto function prompted for in the minibuffer. + +`pascal-outline' + Enter pascal-outline-mode (see also pascal-outline). + + + The variables controlling indentation/edit style are: + +`pascal-indent-level' + Indentation of Pascal statements with respect to containing block. + +`pascal-case-indent' + Indentation for case statements. + +`pascal-auto-newline' + Non-nil means automatically newline after semicolons and the + punctuation mark after an end. + +`pascal-tab-always-indent' + Non-nil means TAB in Pascal mode should always reindent the + current line, regardless of where in the line point is when the + TAB command is used. + +`pascal-auto-endcomments' + Non-nil means a comment { ... } is set after the ends which ends + cases and functions. The name of the function or case will be set + between the braces. + +`pascal-auto-lineup' + List of contexts where auto lineup of :'s or ='s should be done. + + + See also the user variables `pascal-type-keywords', +`pascal-start-keywords' and `pascal-separator-keywords'. + + Turning on Pascal mode calls the value of the variable +`pascal-mode-hook' with no args, if that value is non-nil. + + To configure this package, type: + + M-x customize-group RET pascal RET + + +File: prog-modes.info, Node: php-mode, Next: postscript, Prev: pascal, Up: Top + +21 Editing PHP Code +******************* + +PHP mode is a major mode for editing PHP source code. It is +automatically invoked for buffers visiting the following files of files: + + * any file ending with one of the following extensions: `.phps', + `.php3', `.php4' + + * any file ending with the extension `.phtml' + + * any file ending with the extension `.inc' + + The mode is an extension of cc-mode; thus it inherits all cc-mode's +navigation functionality (*note CC Mode: (cc-mode)Top.). But it colors +according to the PHP grammar and indents according to the PEAR coding +guidelines. It also includes a couple of handy IDE-type features such +as documentation search and a source and class browser. + + For colorization, turn on `global-font-lock' or add the following to +your `user-init-file': + + (add-hook 'php-mode-user-hook 'turn-on-font-lock) + + To use abbrev-mode, add lines like this to your `user-init-file': + + (add-hook 'php-mode-user-hook + '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends"))) + + To make php-mode compatible with html-mode, see +`http://php-mode.sourceforge.net/'. + + To configure this package, type: + + M-x customize-group RET php RET + +* Menu: + +* About PHP: about-php. + + +File: prog-modes.info, Node: about-php, Prev: php-mode, Up: php-mode + +21.1 About PHP +============== + +PHP is a widely-used general-purpose scripting language that is +especially suited for Web development and can be embedded into HTML. +For more information, see `http://www.php.net/'. + + +File: prog-modes.info, Node: postscript, Next: prolog, Prev: php-mode, Up: Top + +22 Editing PostScript Programs +****************************** + +This mode is used for editing PostScript programs. It is automatically +invoked for buffers visiting any file ending with an extension of `.cps' +or `.ps'. + + `C-c C-c' will send the contents of the buffer to the NeWS server +using psh(1). `C-c |' sends the current region. `C-c !' starts an +interactive psh(1) window which will be used for subsequent `C-c C-c' or +`C-c |' commands. + + In this mode, `TAB' and `M-C-\' attempt to indent code based on the +position of {}, [], and begin/end pairs. The variable +`ps-indent-level' controls the amount of indentation used inside arrays +and begin/end pairs. + + The following key mappings are defined: + +`tab' ps-tab +`C-c' << Prefix Command >> +`C-i' ps-tab +`C-c !' ps-shell +`C-c |' ps-execute-region +`C-c C-c' ps-execute-buffer + + `M-x postscript-mode' calls the value of the variable +`postscript-mode-hook' with no args, if that value is non-nil. + + To configure this package please view the source code. This can be +done by typing `C-x 4 l postscript'. + +* Menu: + +* About PostScript: about-postscript. + + +File: prog-modes.info, Node: about-postscript, Prev: postscript, Up: postscript + +22.1 About PostScript +===================== + +PostScript is a programming language optimized for printing graphics +and text (whether on paper, film, or CRT is immaterial). In the jargon +of the day, it is a page description language. It was introduced by +Adobe in 1985 and first (to my knowledge) appeared in the Apple +LaserWriter. The main purpose of PostScript was to provide a convenient +language in which to describe images in a device independent manner. +This device independence means that the image is described without +reference to any specific device features (e.g. printer resolution) so +that the same description could be used on any PostScript printer (say, +a LaserWriter or a Linotron) without modification. + + +File: prog-modes.info, Node: prolog, Next: rexx-mode, Prev: postscript, Up: Top + +23 Editing and Running Prolog Code +********************************** + +This mode is used for editing Prolog code. It is automatically invoked +for buffers visiting any file ending with an of extension `.prolog'. + + The mode knows about Prolog syntax and comments, and can send +regions to an inferior Prolog interpreter process. + + Blank lines and `%%...' separate paragraphs. `%'s start comments. + + The following key mappings are defined: + +`tab' prolog-indent-line +`C-i' prolog-indent-line +`M-C-x' prolog-consult-region + + Entry to this mode calls the value of `prolog-mode-hook' if that +value is non-nil. + + To configure this package, type: + + M-x customize-group RET prolog RET + + +File: prog-modes.info, Node: rexx-mode, Next: rpm-spec-mode, Prev: prolog, Up: Top + +24 Editing REXX Code +******************** + +This mode is used for editing REXX code. It is automatically invoked +for buffers visiting the following types of files: + + * any file ending with an extension of `.rexx'. + + * any file that has an interpretor line (the "shebang" line) + specifying "rexx". + + The following key mappings are defined: + +`backspace' backward-delete-char-untabify +`return' rexx-indent-and-newline +`tab' rexx-indent-command +`C-c' << Prefix Command >> +`C-i' rexx-indent-command +`C-m' rexx-indent-and-newline +`C-c C-c' rexx-debug +`C-c C-p' rexx-find-matching-do + + The following variables control indentation style: + +`rexx-indent' + The basic indentation for do-blocks. + +`rexx-end-indent' + The relative offset of the \"end\" statement. 0 places it in the + same column as the statements of the block. Setting it to the same + value as rexx-indent places the \"end\" under the do-line. + +`rexx-cont-indent' + The indention for lines following \"then\", \"else\" and \",\" + (continued) lines. + +`rexx-tab-always-indent' + Non-nil means TAB in REXX mode should always reindent the current + line, regardless of where in the line the point is when the TAB + command is used. + + + If you have set `rexx-end-indent' to a nonzero value, you probably +want to remap `RETURN' to `rexx-indent-newline-indent'. It makes sure +that lines indents correctly when you press `RETURN'. + + An extensive abbreviation table consisting of all the keywords of +REXX are supplied. Expanded keywords are converted into upper case +making it easier to distinguish them. To use this feature the buffer +must be in `abbrev-mode'. (See example below.) + + Turning on REXX mode calls the value of the variable `rexx-mode-hook' +with no args, if that value is non-nil. + + For example: + + (setq rexx-mode-hook '(lambda () + (setq rexx-indent 4) + (setq rexx-end-indent 4) + (setq rexx-cont-indent 4) + (local-set-key \"\\C-m\" 'rexx-indent-newline-indent) + (abbrev-mode 1) + )) + + will make the END aligned with the DO/SELECT. It will indent blocks +and IF-statements four steps and make sure that the END jumps into the +correct position when RETURN is pressed. Finally it will use the +abbrev table to convert all REXX keywords into upper case. + + To configure this package, type: + + M-x customize-group RET rexx RET + +* Menu: + +* About REXX: about-rexx. + + +File: prog-modes.info, Node: about-rexx, Prev: rexx-mode, Up: rexx-mode + +24.1 About REXX +=============== + +REXX is a programming language designed by Michael Cowlishaw of IBM UK +Laboratories. Rexx is an acronym which stands for "Restructured +Extended Executor Language". In Mike's own words: "REXX is a +procedural language that allows programs and algorithms to be written +in a clear and structured way." + + +File: prog-modes.info, Node: rpm-spec-mode, Next: simula, Prev: rexx-mode, Up: Top + +25 Editing RPM Spec Files +************************* + +This mode is used for editing spec files for building RPM packages. It +is automatically invoked for buffers visiting any file ending with an +extension of `.spec?' or `.spec.in'. + + The mode much like C mode except for the syntax of comments. It +uses the same keymap as C mode and has the same variables for +customizing indentation. It has its own abbrev table and its own +syntax table. *Note CC Mode: (cc-mode)Top., for details. + + Turning on RPM spec mode calls the value of the variable +`rpm-spec-mode-hook' with no args, if that value is non-nil. + + To configure this package, type: + + M-x customize-group RET rpm-spec RET + +* Menu: + +* About RPM: about-rpm. + + +File: prog-modes.info, Node: about-rpm, Prev: rpm-spec-mode, Up: rpm-spec-mode + +25.1 About RPM +============== + +The RPM Package Manager (RPM) is a powerful command line driven package +management system capable of installing, uninstalling, verifying, +querying, and updating computer software packages. Each software +package consists of an archive of files along with information about +the package like its version, a description, and the like. There is +also a related API ("Application Program Interface"), permitting +advanced developers to bypass 'shelling out' to a command line, and to +manage such transactions from within a native coding language. + + For more information, see `http://www.rpm.org/'. + + +File: prog-modes.info, Node: simula, Next: sql, Prev: rpm-spec-mode, Up: Top + +26 Editing SIMULA 87 Code +************************* + +This mode is used for editing SIMULA code. It is NOT automatically +invoked for any particular file extension. To invoke this mode while +editing a file, type `M-x simula-mode'. + + The mode knows about Simula syntax and standard indentation +commands. It also provides convenient abbrevs for Simula keywords. + + The following key mappings are defined: + +`:' simula-electric-label +`tab' simula-indent-command +`C-c' << Prefix Command >> +`C-i' simula-indent-command +`C-c C-d' simula-forward-down-level +`C-c C-n' simula-next-statement +`C-c C-p' simula-previous-statement +`C-c C-u' simula-backward-up-level + + The following variables controlling indentation style: + +`simula-tab-always-indent' + Non-nil means TAB in SIMULA mode should always reindent the + current line, regardless of where in the line point is when the + TAB command is used. + +`simula-indent-level' + Indentation of SIMULA statements with respect to containing block. + +`simula-substatement-offset' + Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE. + +`simula-continued-statement-offset' + Extra indentation for lines not starting a statement or + substatement, e.g. a nested FOR-loop. If value is a list, each + line in a multiple- line continued statement will have the car of + the list extra indentation with respect to the previous line of + the statement. + +`simula-label-offset -4711' + Offset of SIMULA label lines relative to usual indentation. + +`simula-if-indent '(0 . 0)' + Extra indentation of THEN and ELSE with respect to the starting IF. + Value is a cons cell, the car is extra THEN indentation and the cdr + extra ELSE indentation. IF after ELSE is indented as the starting + IF. + +`simula-inspect-indent '(0 . 0)' + Extra indentation of WHEN and OTHERWISE with respect to the + corresponding INSPECT. Value is a cons cell, the car is extra + WHEN indentation and the cdr extra OTHERWISE indentation. + +`simula-electric-indent nil' + If this variable is non-nil, `simula-indent-line' will check the + previous line to see if it has to be reindented. + +`simula-abbrev-keyword 'upcase' + Determine how SIMULA keywords will be expanded. Value is one of + the symbols `upcase', `downcase', `capitalize', (as in) + `abbrev-table', or nil if they should not be changed. + +`simula-abbrev-stdproc 'abbrev-table' + Determine how standard SIMULA procedure and class names will be + expanded. Value is one of the symbols `upcase', `downcase', + `capitalize', (as in) `abbrev-table', or nil if they should not be + changed. + + + Turning on SIMULA mode calls the value of the variable +`simula-mode-hook' with no arguments, if that value is non-nil. + + Warning: `simula-mode-hook' should not read in an abbrev file without +calling the function `simula-install-standard-abbrevs' afterwards, +preferably not at all. + + To configure this package, type: + + M-x customize-group RET simula RET + +* Menu: + +* About SIMULA: about-simula. + + +File: prog-modes.info, Node: about-simula, Prev: simula, Up: simula + +26.1 About SIMULA +================= + +The SIMULA programming language was designed and built by Ole-Johan +Dahl and Kristen Nygaard at the Norwegian Computing Center (NCC) in +Oslo between 1962 and 1967. It was originally designed and implemented +as a language for discrete event simulation, but was later extended and +reimplemented as a full scale general purpose programming language. + + For more information, see +`http://www.engin.umd.umich.edu/CIS/course.des/cis400/simula/simula.html'. + + +File: prog-modes.info, Node: sql, Next: tcl, Prev: simula, Up: Top + +27 Specialized Mode for SQL Interpreters +**************************************** + +This package provides a `sql-mode' and a `sql-interactive-mode'. The +goals were two simple modes providing syntactic highlighting. The +interactive mode had to provide a command-line history; the other mode +had to provide "send region/buffer to SQL interpreter" functions. +"simple" in this context means easy to use, easy to maintain and little +or no bells and whistles. + + `sql-interactive-mode' is used to interact with a SQL interpreter +process in a SQLi buffer (usually called `*SQL*'). The SQLi buffer is +created by calling a SQL interpreter-specific entry function. Do _not_ +call `sql-interactive-mode' by itself. + + The list of currently supported interpreters and the corresponding +entry function used to create the SQLi buffers is shown with `M-x +sql-help'. + + Since `sql-interactive-mode' is built on top of the general +command-interpreter-in-a-buffer mode (comint mode), it shares a common +base functionality, and a common set of bindings, with all modes +derived from comint mode. This makes these modes easier to use. + + `sql-mode' can be used to keep editing SQL statements. The SQL +statements can be sent to the SQL process in the SQLi buffer. + + For documentation on the functionality provided by comint mode, and +the hooks available for customizing it, see the file `comint.el'. + + Hint for newbies: take a look at `dabbrev-expand', `abbrev-mode', +and `imenu-add-menubar-index'. + + To configure this package, type: + + M-x customize-group RET SQL RET + + +File: prog-modes.info, Node: tcl, Next: teco, Prev: sql, Up: Top + +28 Editing Tcl Code +******************* + +This mode is used to edit Tcl code. The mode is automatically invoked +for buffers visiting the following types of files: + + * any file ending with an extension of `.tcl' or `.exp'. + + * any file that has an interpretor line (the "shebang" line) + specifying "scope", "wish", "tcl", "tclsh", or "expect". + + The mode provides the following capabilities: + + * Expression and list commands understand all Tcl brackets. + + * Tab indents for Tcl code. + + * Paragraphs are separated by blank lines only. + + * Delete converts tabs to spaces as it moves back. + + The variables controlling indentation style are: + +`tcl-indent-level' + Indentation of Tcl statements within surrounding block. + +`tcl-continued-indent-level' + Indentation of continuation line relative to first line of command. + + + The variables controlling user interaction with mode (see variable +documentation for details) are: + +`tcl-tab-always-indent' + Controls action of TAB key. + +`tcl-auto-newline' + Non-nil means automatically newline before and after braces, + brackets, and semicolons inserted in Tcl code. + +`tcl-electric-hash-style' + Controls action of `#' key. + +`tcl-use-hairy-comment-detector' + If t, use more complicated, but slower, comment detector. This + variable is only used in Emacs 19. + +`tcl-use-smart-word-finder' + If not nil, use a smarter, Tcl-specific way to find the current + word when looking up help on a Tcl command. + + + Turning on Tcl mode calls the value of the variable `tcl-mode-hook' +with no args, if that value is non-nil. Read the documentation for +`tcl-mode-hook' to see what kinds of interesting hook functions already +exist. + + The following key mappings are defined: + +`#' tcl-electric-hash +`;' tcl-electric-char +`[' tcl-electric-char +`]' tcl-electric-char +`{' tcl-electric-char +`}' tcl-electric-brace +`delete' backward-delete-char-untabify +`tab' tcl-indent-command +`C-c' << Prefix Command >> +`C-i' tcl-indent-command +`M-;' tcl-indent-for-comment +`M-backspace' tcl-mark-defun +`M-C-a' tcl-beginning-of-defun +`M-C-e' tcl-end-of-defun +`M-C-h' tcl-mark-defun +`M-C-q' indent-tcl-exp +`M-C-x' tcl-eval-defun +`C-c tab' tcl-help-on-word +`C-c C-b' tcl-submit-bug-report +`C-c C-c' comment-region +`C-c C-f' tcl-load-file +`C-c C-i' tcl-help-on-word +`C-c C-s' switch-to-tcl +`C-c C-t' inferior-tcl +`C-c C-v' tcl-eval-defun +`C-c C-x' tcl-eval-region + + To configure this package, type: + + M-x customize-group RET tcl RET + +* Menu: + +* About Tcl: about-tcl. + + +File: prog-modes.info, Node: about-tcl, Prev: tcl, Up: tcl + +28.1 About Tcl +============== + +Tcl (Tool Command Language) is used by over half a million developers +worldwide and has become a critical component in thousands of +corporations. It has a simple and programmable syntax and can be either +used as a standalone application or embedded in application programs. +Best of all, Tcl is open source so it's completely free. + + Tk is a graphical user interface toolkit that makes it possible to +create powerful GUIs incredibly quickly. It proved so popular that it +now ships with all distributions of Tcl. + + For more information, see `http://www.tcl.tk/software/tcltk/'. + + +File: prog-modes.info, Node: teco, Next: uil-mode, Prev: tcl, Up: Top + +29 Teco Interpreter +******************* + +This package implements a Teco Interpreter. + + To configure this package please view the source code. This can be +done by typing `C-x 4 l teco'. + + +File: prog-modes.info, Node: uil-mode, Next: verilog-mode, Prev: teco, Up: Top + +30 Editing Motif UIL Code +************************* + +This mode is used to edit Motif UIL files. It is automatically invoked +for buffers visiting any file ending with an extension of `.uil'. + + This mode is much like C mode except for the syntax of comments. It +uses the same keymap as C mode and has the same variables for +customizing indentation. It has its own abbrev table and its own +syntax table. *Note CC Mode: (cc-mode)Top., for details. + + Turning on uilmode calls the value of the variable `uil-mode-hook' +with no args, if that value is non-nil. + + To configure this package please view the source code. This can be +done by typing `C-x 4 l uil-mode'. + +* Menu: + +* About UIL: about-uil. + + +File: prog-modes.info, Node: about-uil, Prev: uil-mode, Up: uil-mode + +30.1 About UIL +============== + +The Motif user interface language (UIL) is a specification language for +describing the initial state of a Motif application's user interface. + + +File: prog-modes.info, Node: verilog-mode, Next: vrml-mode, Prev: uil-mode, Up: Top + +31 Editing Verilog HDL Source +***************************** + +This mode is used to edit Verilog source files. It is automatically +invoked for buffers visiting any file ending with one of the following +extensions: `.vh?', `.dv', `.vlog', and `.verilog'. + + The mode provides the following features: + + * NEWLINE, TAB indents for Verilog code. + + * Delete converts tabs to spaces as it moves back. + + * Supports highlighting. + + The variables controlling indentation/edit style are: + +`verilog-indent-level' + Indentation of Verilog statements with respect to containing block. + +`verilog-indent-level-module' + Absolute indentation of Module level Verilog statements. Set to 0 + to get initial and always statements lined up on the left side of + your screen. + +`verilog-indent-level-declaration' + Indentation of declarations with respect to containing block. Set + to 0 to get them list right under containing block. + +`verilog-indent-level-behavioral' + Indentation of first begin in a task or function block Set to 0 to + get such code to lined up underneath the task or function keyword + +`verilog-indent-level-directive' + Indentation of `ifdef/`endif blocks + +``verilog-cexp-indent' + Indentation of Verilog statements broken across lines i.e.: + if (a) + begin + +`verilog-case-indent' + Indentation for case statements. + +`verilog-auto-newline' + Non-nil means automatically newline after semicolons and the + punctuation mark after an end. + +`verilog-auto-indent-on-newline' + Non-nil means automatically indent line after newline + +`verilog-tab-always-indent' + Non-nil means TAB in Verilog mode should always reindent the + current line, regardless of where in the line point is when the + TAB command is used. + +`verilog-indent-begin-after-if' + Non-nil means to indent begin statements following a preceding if, + else, while, for and repeat statements, if any. otherwise, the + begin is lined up with the preceding token. If t, you get: + if (a) + begin // amount of indent based on `verilog-cexp-indent' + + otherwise you get: + if (a) + begin + +`verilog-auto-endcomments' + Non-nil means a comment /* ... */ is set after the ends which ends + cases, tasks, functions and modules. The type and name of the + object will be set between the braces. + +`verilog-minimum-comment-distance' + Minimum distance (in lines) between begin and end required before + a comment will be inserted. Setting this variable to zero results + in every end acquiring a comment; the default avoids too many + redundant comments in tight quarters. + +`verilog-auto-lineup' + List of contexts where auto lineup of :'s or ='s should be done. + + + Turning on Verilog mode calls the value of the variable +`verilog-mode-hook' with no args, if that value is non-nil. + + Other useful functions are: + +`verilog-complete-word' + complete word with appropriate possibilities (functions, verilog + keywords...) + +`verilog-comment-region' + Put marked area in a comment, fixing nested comments. + +`verilog-uncomment-region' + Uncomment an area commented with `verilog-comment-region'. + +`verilog-insert-block' + insert begin ... end; + +`verilog-star-comment' + insert /* ... */ + +`verilog-mark-defun' + Mark function. + +`verilog-beg-of-defun' + Move to beginning of current function. + +`verilog-end-of-defun' + Move to end of current function. + +`verilog-label-be' + Label matching begin ... end, fork ... join and case ... endcase + statements + +`verilog-sk-always' + Insert a always @(AS) begin .. end block + +`verilog-sk-begin' + Insert a begin .. end block + +`verilog-sk-case' + Insert a case block, prompting for details + +`verilog-sk-else' + Insert an else begin .. end block + +`verilog-sk-for' + Insert a for (...) begin .. end block, prompting for details + +`verilog-sk-generate' + Insert a generate .. endgenerate block + +`verilog-sk-header' + Insert a nice header block at the top of file + +`verilog-sk-initial' + Insert an initial begin .. end block + +`verilog-sk-fork' + Insert a fork begin .. end .. join block + +`verilog-sk-module' + Insert a module .. (/*AUTOARG*/);.. endmodule block + +`verilog-sk-primitive' + Insert a primitive .. (.. );.. endprimitive block + +`verilog-sk-repeat' + Insert a repeat (..) begin .. end block + +`verilog-sk-specify' + Insert a specify .. endspecify block + +`verilog-sk-task' + Insert a task .. begin .. end endtask block + +`verilog-sk-while' + Insert a while (...) begin .. end block, prompting for details + +`verilog-sk-casex' + Insert a casex (...) item: begin.. end endcase block, prompting + for details + +`verilog-sk-casez' + Insert a casez (...) item: begin.. end endcase block, prompting + for details + +`verilog-sk-if' + Insert an if (..) begin .. end block + +`verilog-sk-else-if' + Insert an else if (..) begin .. end block + +`verilog-sk-comment' + Insert a comment block + +`verilog-sk-assign' + Insert an assign .. = ..; statement + +`verilog-sk-function' + Insert a function .. begin .. end endfunction block + +`verilog-sk-input' + Insert an input declaration, prompting for details + +`verilog-sk-output' + Insert an output declaration, prompting for details + +`verilog-sk-state-machine' + Insert a state machine definition, prompting for details! + +`verilog-sk-inout' + Insert an inout declaration, prompting for details + +`verilog-sk-wire' + Insert a wire declaration, prompting for details + +`verilog-sk-reg' + Insert a register declaration, prompting for details" + + + To configure this package, type: + + M-x customize-group RET verilog-mode RET + +* Menu: + +* About Verilog: about-verilog. + + +File: prog-modes.info, Node: about-verilog, Prev: verilog-mode, Up: verilog-mode + +31.1 About Verilog +================== + +Verilog HDL is a hardware description language used to design and +document electronic systems. Verilog HDL allows designers to design at +various levels of abstraction. It is the most widely used HDL with a +user community of more than 50,000 active designers. + + For more information, see `http://www.verilog.com/'. + + +File: prog-modes.info, Node: vrml-mode, Next: XEmacs License, Prev: verilog-mode, Up: Top + +32 Editing VRML (.wrl) Files +**************************** + +This mode is used for editing VRML files. It is automatically invoked +for buffers visiting any file ending with an extension of `.wrl'. + + The mode has the following features: + + * Expression and list commands understand all VRML brackets. + + * Tab indents for VRML code. + + * Paragraphs are separated by blank lines only. + + * Delete converts tabs to spaces as it moves back. + + + The variables controlling indentation style are: + +`vrml-indent-level' + Indentation of VRML statements within surrounding block. + + + The variables controlling user interaction with mode (see variable +documentation for details) are: + +`vrml-tab-always-indent' + Controls action of TAB key. + +`vrml-auto-newline' + Non-nil means automatically newline before and after braces + inserted in VRML code. + + + Turning on VRML mode calls the value of the variable `vrml-mode-hook' +with no args, if that value is non-nil. Read the documentation for +`vrml-mode-hook' to see what kinds of interesting hook functions already +exist. + + To configure this package, type: + + M-x customize-group RET vrml RET + + +File: prog-modes.info, Node: XEmacs License, Prev: vrml-mode, Up: Top + +33 XEmacs License +***************** + +GNU GENERAL PUBLIC LICENSE +************************** + + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble +======== + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", + below, refers to any such program or work, and a "work based on + the Program" means either the Program or any derivative work under + copyright law: that is to say, a work containing the Program or a + portion of it, either verbatim or with modifications and/or + translated into another language. (Hereinafter, translation is + included without limitation in the term "modification".) Each + licensee is addressed as "you". + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running the Program is not restricted, and the output from the + Program is covered only if its contents constitute a work based on + the Program (independent of having been made by running the + Program). Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any + warranty; and give any other recipients of the Program a copy of + this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b. You must cause any work that you distribute or publish, that + in whole or in part contains or is derived from the Program + or any part thereof, to be licensed as a whole at no charge + to all third parties under the terms of this License. + + c. If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display + an announcement including an appropriate copyright notice and + a notice that there is no warranty (or else, saying that you + provide a warranty) and that users may redistribute the + program under these conditions, and telling the user how to + view a copy of this License. (Exception: if the Program + itself is interactive but does not normally print such an + announcement, your work based on the Program is not required + to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Program, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Program, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Program. + + In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you also do one of the + following: + + a. Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Sections 1 and 2 above on a medium customarily used for + software interchange; or, + + b. Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or, + + c. Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with + such an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete + source code means all the source code for all modules it contains, + plus any associated interface definition files, plus the scripts + used to control compilation and installation of the executable. + However, as a special exception, the source code distributed need + not include anything that is normally distributed (in either + source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable + runs, unless that component itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Program or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Program (or any work + based on the Program), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program + subject to these terms and conditions. You may not impose any + further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Program at all. For example, if a patent license would not permit + royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Program under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 9. The Free Software Foundation may publish revised and/or new + versions of the General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Program + does not specify a version number of this License, you may choose + any version ever published by the Free Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the + author to ask for permission. For software which is copyrighted + by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision + will be guided by the two goals of preserving the free status of + all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY + OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) 19YY NAME OF AUTHOR + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Also add information on how to contact you by electronic and paper +mail. + + If the program is interactive, make it output a short notice like +this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + + The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + SIGNATURE OF TY COON, 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Library General Public License instead of this License. + + + +Tag Table: +Node: Top218 +Node: Copying3067 +Node: asm-mode7216 +Node: autoconf-mode8361 +Node: about-autoconf8943 +Node: awk-mode9484 +Node: about-awk10401 +Node: cl-indent10608 +Node: cvs11143 +Node: about-cvs12189 +Node: diff-mode12459 +Node: eiffel13740 +Node: about-eiffel14624 +Node: icon15027 +Node: about-icon17229 +Node: javascript-mode17715 +Node: about-javascript20137 +Node: ksh-mode20392 +Node: lua-mode23537 +Node: about-lua23903 +Node: m4-mode24265 +Node: about-m424977 +Node: make-mode25420 +Node: about-make31014 +Node: mode-compile31330 +Node: compile-cust33760 +Node: compile-compilation-mode34937 +Node: compile-makefile-mode35158 +Node: compile-emacs-lisp-mode35527 +Node: compile-dired-mode35920 +Node: compile-sh-mode36498 +Node: compile-c?perl-mode36794 +Node: compile-tcl-mode37038 +Node: compile-c-mode37272 +Node: compile-ada-mode38890 +Node: compile-fortran-mode39172 +Node: compile-java-mode39397 +Node: compile-python-mode39627 +Node: compile-message-mode39878 +Node: compile-catchall40064 +Node: modula240802 +Node: about-modula242370 +Node: old-c-mode42943 +Node: p445154 +Node: about-perforce45620 +Node: pascal46213 +Node: php-mode48545 +Node: about-php49874 +Node: postscript50163 +Node: about-postscript51386 +Node: prolog52192 +Node: rexx-mode52979 +Node: about-rexx55670 +Node: rpm-spec-mode56082 +Node: about-rpm56898 +Node: simula57607 +Node: about-simula60762 +Node: sql61326 +Node: tcl62967 +Node: about-tcl65761 +Node: teco66438 +Node: uil-mode66704 +Node: about-uil67492 +Node: verilog-mode67741 +Node: about-verilog73599 +Node: vrml-mode74042 +Node: XEmacs License75297 + +End Tag Table diff --git a/xemacs-packages/info/re-builder.info b/xemacs-packages/info/re-builder.info new file mode 100644 index 00000000..46817fd3 --- /dev/null +++ b/xemacs-packages/info/re-builder.info @@ -0,0 +1,207 @@ +This is re-builder.info, produced by makeinfo version 4.6 from +re-builder.texi. + +START-INFO-DIR-ENTRY +* re-builder:: Write regular expressions with visual feedback. +END-INFO-DIR-ENTRY + + This file documents the re-builder XEmacs package, which provides +visual feedback when developing regular expressions. + + This documentation was taken from the source file, `re-builder.el', +which is subject to the following conditions; because of the nature of +the GNU GPL, this file is as a result also subject to those conditions. + + Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, +Inc. + + This file is part of GNU Emacs. + + GNU Emacs 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. + + GNU Emacs 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. + + End of permissions notice. + + +File: re-builder.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) + +Re-builder on XEmacs +******************** + +When I have to come up with regular expressions that are more complex +than simple string matchers, especially if they contain sub +expressions, I find myself spending quite some time in the `development +cycle'. `re-builder' aims to shorten this time span so I can get on +with the more interesting bits. + + With it you can have immediate visual feedback about how well the +regexp behaves to your expectations on the intended data. + + This is version 1.2 of the re-builder manual, last updated on +Sunday, July 24, 2005. + +* Menu: + +* Copying:: re-builder copying conditions. +* Overview:: re-builder history and general information. + +For general users: +* Usage:: An overview of the operation of re-builder. +* Regex Types:: Types of regular expression handled. +* Questions:: A couple of selected queries. + + +File: re-builder.info, Node: Copying, Next: Overview, Prev: Top, Up: Top + +re-builder Copying Conditions +***************************** + +Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, +Inc. + + re-builder 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. + + re-builder 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 XEmacs; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + + +File: re-builder.info, Node: Overview, Next: Usage, Prev: Copying, Up: Top + +An Overview of re-builder +************************* + +When I have to come up with regular expressions that are more complex +than simple string matchers, especially if they contain sub expressions, +I find myself spending quite some time in the `development cycle'. +re-builder aims to shorten this time span so I can get on with the more +interesting bits. + + With it you can have immediate visual feedback about how well the +regexp behaves to your expectations on the intended data. + + +File: re-builder.info, Node: Usage, Next: Regex Types, Prev: Overview, Up: Top + +Operation of re-builder +*********************** + +When called up, with `M-x re-builder RET', re-builder attaches itself +to the current buffer which becomes its target buffer, where all the +matching is done. The active window is split so you have a view on the +data while authoring the RE. If the edited expression is valid the +matches in the target buffer are marked automatically with colored +overlays (for non-color displays see below) giving you feedback over the +extents of the matched (sub) expressions. The (non-)validity is shown +only in the modeline without throwing the errors at you. If you want to +know the reason why RE Builder considers it as invalid call +`reb-force-update' (`C-c C-u') which should reveal the error. + + The target buffer can be changed with `reb-change-target-buffer' +(`C-c C-b'). Changing the target buffer automatically removes the +overlays from the old buffer and displays the new one in the target +window. + + re-builder keeps the focus while updating the matches in the target +buffer so corrections are easily incorporated. If you are satisfied +with the result you can paste the RE to the kill-ring with `reb-copy' +(`C-c C-w') (the copied RE and current syntax is displayed in the echo +area), quit re-builder (`C-c C-q') and use it wherever you need it. + + As the automatic updates can take some time on large buffers, they +can be limited by `reb-auto-match-limit' so that they should not have a +negative impact on the editing. Setting it to nil makes even the auto +updates go all the way. Forcing an update overrides this limit allowing +an easy way to see all matches. + + +File: re-builder.info, Node: Regex Types, Next: Questions, Prev: Usage, Up: Top + +Regex Types +*********** + +Currently re-builder understands six different forms of input, namely +`lisp-re', `perl', `read', `rx', `sregex', and `string' syntax. Read +syntax and string syntax are both delimited by `"'s and behave +according to their name. With the `perl' and `string' syntax there's +no need to escape the backslashes and double quotes simplifying the +editing somewhat. The other four allow editing of symbolic regular +expressions supported by the packages of the same name. (`lisp-re' is +a package by me and its support may go away as it is nearly the same as +the `sregex' package in Emacs) + + Note that the `sregex,' `rx' and `lisp-re' syntaxes will only be +available in XEmacs if you've installed them yourself. + + Editing symbolic expressions is done through a major mode derived +from `emacs-lisp-mode' so you'll get all the good stuff like automatic +indentation and font-locking etc. + + When editing a symbolic regular expression, only the first expression +in the RE Builder buffer is considered, which helps limiting the extent +of the expression like the `"'s do for the text modes. For the +`sregex' syntax the function `sregex' is applied to the evaluated +expression read. So you can use quoted arguments with something like +'("findme") or you can construct arguments to your heart's content with +a valid ELisp expression. The compiled string form will be copied by +`reb-copy'. If you want to take a glance at the corresponding string +you can temporarily change the input syntax using `reb-change-syntax' +(`C-c C-i'). The current RE syntax is also displayed in the modeline. + + Changing the input syntax is transparent (for the obvious exception +non-symbolic -> symbolic) so you can change your mind as often as you +like. + + There is also a shortcut function, `reb-toggle-case' (`C-c C-c'), +for toggling the `case-fold-search' variable in the target buffer with +an immediate update. + + +File: re-builder.info, Node: Questions, Prev: Regex Types, Up: Top + +Questions +********* + +Q: But what if my display cannot show colored overlays? + + A: Then the cursor will flash around the matched text making it stand +out. + + Q: But how can I then make out the sub-expressions? + + A: That's where the `sub-expression mode' comes in. In it only the +digit keys are assigned to perform an update that will flash the +corresponding subexp only. + + + +Tag Table: +Node: Top1369 +Node: Copying2388 +Node: Overview3289 +Node: Usage3853 +Node: Regex Types5555 +Node: Questions7559 + +End Tag Table diff --git a/xemacs-packages/info/smtpmail.info b/xemacs-packages/info/smtpmail.info new file mode 100644 index 00000000..a096ac4f --- /dev/null +++ b/xemacs-packages/info/smtpmail.info @@ -0,0 +1,414 @@ +This is smtpmail.info, produced by makeinfo version 4.7 from +smtpmail.texi. + + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* SMTP: (smtpmail). Emacs library for sending mail via SMTP. +END-INFO-DIR-ENTRY + + +File: smtpmail.info, Node: Top, Next: How Mail Works, Up: (dir) + +Emacs SMTP Library +****************** + +Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +* Menu: + +* How Mail Works:: Brief introduction to mail concepts. +* Emacs Speaks SMTP:: How to use the SMTP library in Emacs. +* Authentication:: Authenticating yourself to the server. +* Queued delivery:: Sending mail without an internet connection. +* Server workarounds:: Mail servers with special requirements. +* Debugging:: Tracking down problems. + +Indices + +* Index:: Index over variables and functions. + + +File: smtpmail.info, Node: How Mail Works, Next: Emacs Speaks SMTP, Prev: Top, Up: Top + +1 How Mail Works +**************** + +On the internet, mail is sent from mail host to mail host using the +simple mail transfer protocol (SMTP). To send and receive mail, you +must get it from and send it to a mail host. Every mail host runs a +mail transfer agent (MTA) such as Exim that accepts mails and passes +them on. The communication between a mail host and other clients does +not necessarily involve SMTP, however. Here is short overview of what +is involved. + + The mail program -- also called a mail user agent (MUA) -- usually +sends outgoing mail to a mail host. When your computer is permanently +connected to the internet, it might even be a mail host itself. In +this case, the MUA will pipe mail to the `/usr/lib/sendmail' +application. It will take care of your mail and pass it on to the next +mail host. + + When you are only connected to the internet from time to time, your +internet service provider (ISP) has probably told you which mail host +to use. You must configure your MUA to use that mail host. Since you +are reading this manual, you probably want to configure Emacs to use +SMTP to send mail to that mail host. More on that in the next section. + + Things are different when reading mail. The mail host responsible +for your mail keeps it in a file somewhere. The messages get into the +file by way of a mail delivery agent (MDA) such as procmail. These +delivery agents often allow you to filter and munge your mails before +you get to see it. When your computer is that mail host, this file is +called a spool, and sometimes located in the directory +`/var/spool/mail/'. All your MUA has to do is read mail from the +spool, then. + + When your computer is not always connected to the internet, you must +get the mail from the remote mail host using a protocol such as POP3 or +IMAP. POP3 essentially downloads all your mail from the mail host to +your computer. The mail is stored in some file on your computer, and +again, all your MUA has to do is read mail from the spool. + + When you read mail from various machines, downloading mail from the +mail host to your current machine is not convenient. In that case, you +will probably want to use the IMAP protocol. Your mail is kept on the +mail host, and you can read it while you are connected via IMAP to the +mail host. + + So how does reading mail via the web work, you ask. In that case, +the web interface just allows you to remote-control a MUA on the web +host. Whether the web host is also a mail host, and how all the pieces +interact is completely irrelevant. You usually cannot use Emacs to +read mail via the web, unless you use software that parses the +ever-changing HTML of the web interface. + + +File: smtpmail.info, Node: Emacs Speaks SMTP, Next: Authentication, Prev: How Mail Works, Up: Top + +2 Emacs Speaks SMTP +******************* + +Emacs includes a package for sending your mail to a SMTP server and +have it take care of delivering it to the final destination, rather +than letting the MTA on your local system take care of it. This can be +useful if you don't have a MTA set up on your host, or if your machine +is often disconnected from the internet. + + Sending mail via SMTP requires configuring your mail user agent +(*note Mail Methods: (emacs)Mail Methods.) to use the SMTP library. +How to do this should be described for each mail user agent; for the +default mail user agent the variable `send-mail-function' (*note Mail +Sending: (emacs)Mail Sending.) is used; for the Message and Gnus user +agents the variable `message-send-mail-function' (*note Mail Variables: +(message)Mail Variables.) is used. + + ;; If you use the default mail user agent. + (setq send-mail-function 'smtpmail-send-it) + ;; If you use Message or Gnus. + (setq message-send-mail-function 'smtpmail-send-it) + + Before using SMTP you must find out the hostname of the SMTP server +to use. Your system administrator should provide you with this +information, but often it is the same as the server you receive mail +from. + +`smtpmail-smtp-server' + The variable `smtpmail-smtp-server' controls the hostname of the + server to use. It is a string with an IP address or hostname. It + defaults to the contents of the `SMTPSERVER' environment variable, + or, if empty, the contents of `smtpmail-default-smtp-server'. + +`smtpmail-default-smtp-server' + The variable `smtpmail-default-smtp-server' controls the default + hostname of the server to use. It is a string with an IP address + or hostname. It must be set before the SMTP library is loaded. + It has no effect if set after the SMTP library has been loaded, or + if `smtpmail-smtp-server' is defined. It is usually set by system + administrators in a site wide initialization file. + + The following example illustrates what you could put in `~/.emacs' +to set the SMTP server name. + + ;; Send mail using SMTP via mail.example.org. + (setq smtpmail-smtp-server "mail.example.org") + + SMTP is normally used on the registered "smtp" TCP service port 25. +Some environments use SMTP in "Mail Submission" mode, which uses port +587. Using other ports is not uncommon, either for security by +obscurity purposes, port forwarding, or otherwise. + +`smtpmail-smtp-service' + The variable `smtpmail-smtp-service' controls the port on the + server to contact. It is either a string, in which case it will be + translated into an integer using system calls, or an integer. + + The following example illustrates what you could put in `~/.emacs' +to set the SMTP service port. + + ;; Send mail using SMTP on the mail submission port 587. + (setq smtpmail-smtp-service 587) + + +File: smtpmail.info, Node: Authentication, Next: Queued delivery, Prev: Emacs Speaks SMTP, Up: Top + +3 Authentication +**************** + +Many environments require SMTP clients to authenticate themselves +before they are allowed to route mail via a server. The two following +variables contains the authentication information needed for this. The +first variable, `smtpmail-auth-credentials', instructs the SMTP library +to use a SASL authentication step, currently only the CRAM-MD5 and +LOGIN mechanisms are supported and will be selected in that order if +the server support both. + + The second variable, `smtpmail-starttls-credentials', instructs the +SMTP library to connect to the server using STARTTLS. This means the +protocol exchange may be integrity protected and confidential by using +TLS, and optionally also authentication of the client. This feature +uses the elisp package `starttls.el' (see it for more information on +customization), which in turn require that at least one of the +following external tools are installed: + + 1. The GNUTLS command line tool `gnutls-cli', you can get it from + `http://www.gnu.org/software/gnutls/'. This is the recommended + tool, mainly because it can verify the server certificates. + + 2. The `starttls' external program, you can get it from + `starttls-*.tar.gz' from `ftp://ftp.opaopa.org/pub/elisp/'. + + It is not uncommon to use both these mechanisms, e.g., to use +STARTTLS to achieve integrity and confidentiality and then use SASL for +client authentication. + +`smtpmail-auth-credentials' + The variable `smtpmail-auth-credentials' contains a list of + hostname, port, username and password tuples. When the SMTP + library connects to a host on a certain port, this variable is + searched to find a matching entry for that hostname and port. If + an entry is found, the authentication process is invoked and the + credentials are used. + + The hostname field follows the same format as + `smtpmail-smtp-server' (i.e., a string) and the port field the + same format as `smtpmail-smtp-service' (i.e., a string or an + integer). The username and password fields, which either can be + `nil' to indicate that the user is prompted for the value + interactively, should be strings with the username and password, + respectively, information that is normally provided by system + administrators. + +`smtpmail-starttls-credentials' + The variable `smtpmail-starttls-credentials' contains a list of + tuples with hostname, port, name of file containing client key, and + name of file containing client certificate. The processing is + similar to the previous variable. The client key and certificate + may be `nil' if you do not wish to use client authentication. + + The following example illustrates what you could put in `~/.emacs' +to enable both SASL authentication and STARTTLS. The server name +(`smtpmail-smtp-server') is HOSTNAME, the server port +(`smtpmail-smtp-service') is PORT, and the username and password are +USERNAME and PASSWORD respectively. + + ;; Authenticate using this username and password against my server. + (setq smtpmail-auth-credentials + '(("HOSTNAME" "PORT" "USERNAME" "PASSWORD"))) + + ;; Note that if PORT is an integer, you must not quote it as a + ;; string. Normally PORT should be the integer 25, and the example + ;; become: + (setq smtpmail-auth-credentials + '(("HOSTNAME" 25 "USERNAME" "PASSWORD"))) + + ;; Use STARTTLS without authentication against the server. + (setq smtpmail-starttls-credentials + '(("HOSTNAME" "PORT" nil nil))) + + +File: smtpmail.info, Node: Queued delivery, Next: Server workarounds, Prev: Authentication, Up: Top + +4 Queued delivery +***************** + +If you connect to the internet via a dialup connection, or for some +other reason don't have permanent internet connection, sending mail +will fail when you are not connected. The SMTP library implements +queued delivery, and the following variable control its behaviour. + +`smtpmail-queue-mail' + The variable `smtpmail-queue-mail' controls whether a simple off + line mail sender is active. This variable is a boolean, and + defaults to `nil' (disabled). If this is non-`nil', mail is not + sent immediately but rather queued in the directory + `smtpmail-queue-dir' and can be later sent manually by invoking + `smtpmail-send-queued-mail' (typically when you connect to the + internet). + +`smtpmail-queue-dir' + The variable `smtpmail-queue-dir' specifies the name of the + directory to hold queued messages. It defaults to + `~/Mail/queued-mail/'. + + The function `smtpmail-send-queued-mail' can be used to send any +queued mail when `smtpmail-queue-mail' is enabled. It is typically +invoked interactively with `M-x smtpmail-send-queued-mail RET' when you +are connected to the internet. + + +File: smtpmail.info, Node: Server workarounds, Next: Debugging, Prev: Queued delivery, Up: Top + +5 Server workarounds +******************** + +Some SMTP servers have special requirements. The following variables +implement support for common requirements. + +`smtpmail-local-domain' + The variable `smtpmail-local-domain' controls the hostname sent in + the first `EHLO' or `HELO' command sent to the server. It should + only be set if the `system-name' function returns a name that + isn't accepted by the server. Do not set this variable unless + your server complains. + +`smtpmail-sendto-domain' + The variable `smtpmail-sendto-domain' makes the SMTP library add + `@' and the specified value to recipients specified in the message + when they are sent using the `RCPT TO' command. Some + configurations of sendmail requires this behaviour. Don't bother + to set this unless you have get an error like: + + Sending failed; SMTP protocol error + + when sending mail, and the debug buffer (*note Debugging::)) + contains an error such as: + + RCPT TO: SOMEONE + 501 SOMEONE: recipient address must contain a domain + + + +File: smtpmail.info, Node: Debugging, Next: Index, Prev: Server workarounds, Up: Top + +6 Debugging +*********** + +Sometimes delivery fails, often with the generic error message `Sending +failed; SMTP protocol error'. Enabling one or both of the following +variables and inspecting a trace buffer will often give clues to the +reason for the error. + +`smtpmail-debug-info' + The variable `smtpmail-debug-info' controls whether to print the + SMTP protocol exchange in the minibuffer, and retain the entire + exchange in a buffer `*trace of SMTP session to SERVER*', where + SERVER is the name of the mail server to which you send mail. + +`smtpmail-debug-verb' + The variable `smtpmail-debug-verb' controls whether to send the + `VERB' token to the server. The `VERB' server instructs the + server to be more verbose, and often also to attempt final delivery + while your SMTP session is still running. It is usually only + useful together with `smtpmail-debug-info'. Note that this may + cause mail delivery to take considerable time if the final + destination cannot accept mail. + + + +File: smtpmail.info, Node: Index, Prev: Debugging, Up: Top + +7 Index +******* + +7.1 Concept Index +================= + +[index] +* Menu: + +* CRAM-MD5: Authentication. (line 6) +* Dialup connection: Queued delivery. (line 6) +* IMAP: How Mail Works. (line 36) +* ISP: How Mail Works. (line 21) +* LOGIN: Authentication. (line 6) +* Mail Submission: Emacs Speaks SMTP. (line 50) +* MDA: How Mail Works. (line 27) +* MTA: How Mail Works. (line 6) +* MUA: How Mail Works. (line 14) +* POP3: How Mail Works. (line 36) +* SASL: Authentication. (line 6) +* SMTP: How Mail Works. (line 6) +* STARTTLS: Authentication. (line 6) +* Webmail: How Mail Works. (line 48) + +7.2 Function and Variable Index +=============================== + +[index] +* Menu: + +* smtpmail-auth-credentials: Authentication. (line 34) +* smtpmail-debug-info: Debugging. (line 12) +* smtpmail-debug-verb: Debugging. (line 18) +* smtpmail-default-smtp-server: Emacs Speaks SMTP. (line 37) +* smtpmail-local-domain: Server workarounds. (line 10) +* smtpmail-queue-dir: Queued delivery. (line 21) +* smtpmail-queue-mail: Queued delivery. (line 12) +* smtpmail-send-queued-mail: Queued delivery. (line 25) +* smtpmail-sendto-domain: Server workarounds. (line 17) +* smtpmail-smtp-server: Emacs Speaks SMTP. (line 31) +* smtpmail-smtp-service: Emacs Speaks SMTP. (line 56) +* smtpmail-starttls-credentials: Authentication. (line 51) +* SMTPSERVER: Emacs Speaks SMTP. (line 31) + + + +Tag Table: +Node: Top1239 +Node: How Mail Works2792 +Node: Emacs Speaks SMTP5570 +Node: Authentication8533 +Node: Queued delivery12174 +Node: Server workarounds13439 +Node: Debugging14620 +Node: Index15737 + +End Tag Table diff --git a/xemacs-packages/info/speedbar.info b/xemacs-packages/info/speedbar.info new file mode 100644 index 00000000..00ddfe89 --- /dev/null +++ b/xemacs-packages/info/speedbar.info @@ -0,0 +1,1318 @@ +This is speedbar.info, produced by makeinfo version 4.6 from +speedbar.texi. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Speedbar: (speedbar). File/Tag summarizing utility. +END-INFO-DIR-ENTRY + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being "The GNU Manifesto", "Distribution" and "GNU +GENERAL PUBLIC LICENSE", with the Front-Cover texts being "A GNU +Manual", and with the Back-Cover Texts as in (a) below. A copy of the +license is included in the section entitled "GNU Free Documentation +License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and +modify this GNU Manual, like GNU software. Copies published by the Free +Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU Free +Documentation License. If you want to distribute this document +separately from the collection, you can do so by adding a copy of the +license to the document, as described in section 6 of the license. + + +File: speedbar.info, Node: Top, Up: (dir)Top + + Speedbar is a program for Emacs which can be used to summarize +information related to the current buffer. Its original inspiration is +the `explorer' often used in modern development environments, office +packages, and web browsers. + + Speedbar displays a narrow frame in which a tree view is shown. This +tree view defaults to containing a list of files and directories. Files +can be `expanded' to list tags inside. Directories can be expanded to +list the files within itself. Each file or tag can be jumped to +immediately. + + Speedbar expands upon `explorer' windows by maintaining context with +the user. For example, when using the file view, the current buffer's +file is highlighted. Speedbar also mimics the explorer windows by +providing multiple display modes. These modes come in two flavors. +Major display modes remain consistent across buffers, and minor display +modes appear only when a buffer of the applicable type is shown. This +allows authors of other packages to provide speedbar summaries +customized to the needs of that mode. + + Throughout this manual, activities are defined as `clicking on', or +`expanding' items. Clicking means using using `Mouse-2' on a button. +Expanding refers to clicking on an expansion button to display an +expanded summary of the entry the expansion button is on. *Note Basic +Navigation::. + +* Menu: + +* Introduction:: Basics of speedbar. +* Basic Navigation:: Basics of speedbar common between all modes. +* File Mode:: Summarizing files. +* Buffer Mode:: Summarizing buffers. +* Minor Modes:: Additional minor modes such as Info and RMAIL. +* Customizing:: Changing speedbar behavior. +* Extending:: Extend speedbar for your own project. +* Index:: + + +File: speedbar.info, Node: Introduction, Next: Basic Navigation, Up: Top + +Introduction +************ + +To start using speedbar use the command `M-x speedbar RET' or select it +from the Tools menu in versions of Emacs with speedbar installed by +default. This command will open a new frame to summarize the local +files. On X Window systems or on MS-Windows, speedbar's frame is twenty +characters wide, and will mimic the height of the frame from which it +was started. It positions itself to the left or right of the frame you +started it from. + + To use speedbar effectively, it is important to understand its +relationship with the frame you started it from. This frame is the +"attached frame" which speedbar will use as a reference point. Once +started, speedbar watches the contents of this frame, and attempts to +make its contents relevant to the buffer loaded into the attached +frame. In addition, all requests made in speedbar that require the +display of another buffer will display in the attached frame. + + When used in terminal mode, the new frame appears the same size as +the terminal. Since it is not visible while working in the attached +frame, speedbar will save time by using the "slowbar mode", where no +tracking is done until speedbar is requested to show itself (i.e., the +speedbar's frame becomes the selected frame). + + The function to use when switching between frames using the keyboard +is `speedbar-get-focus'. This function will toggle between frames, and +it's useful to bind it to a key in terminal mode. *Note Customizing::. + + +File: speedbar.info, Node: Basic Navigation, Next: File Mode, Prev: Introduction, Up: Top + +Basic Navigation +**************** + +Speedbar can display different types of data, and has several display +and behavior modes. These modes all have a common behavior, menu +system, and look. If one mode is learned, then the other modes are easy +to use. + +* Menu: + +* Basic Key Bindings:: +* Basic Visuals:: +* Mouse Bindings:: +* Displays Submenu:: + + +File: speedbar.info, Node: Basic Key Bindings, Next: Basic Visuals, Prev: Basic Navigation, Up: Basic Navigation + +Basic Key Bindings +================== + +These key bindings are common across all modes: + +`delete, SPC' + Scroll up and down one page. + +`Q' + Quit speedbar, and kill the frame. + +`q' + Quit speedbar, and hide the frame. This makes it faster to + restore the speedbar frame, than if you press `Q'. + +`g' + Refresh whatever contents are in speedbar. + +`t' + Toggle speedbar to and from slowbar mode. In slowbar mode, frame + tracking is not done. + +`n' +`p' + Move, respectively, to the next or previous item. A summary of + that item will be displayed in the attached frame's minibuffer. + +`M-n' +`M-p' + Move to the next or previous item in a restricted fashion. If a + list is open, the cursor will skip over it. If the cursor is in + an open list, it will not leave it. + +`C-M-n' +`C-M-n' + Move forwards and backwards across extended groups. This lets you + quickly skip over all files, directories, or other common + sub-items at the same current depth. + +`C-x b' + Switch buffers in the attached frame. + + Speedbar can handle multiple modes. Two are provided by default. +These modes are File mode, and Buffers mode. There are accelerators to +switch into these different modes. + +`b' + Switch into Quick Buffers mode (*note Buffer Mode::). After one + use, the previous display mode is restored. + +`f' + Switch into File mode. + +`r' + Switch back to the previous mode. + + Some modes provide groups, lists and tags. *Note Basic Visuals::. +When these are available, some additional common bindings are available. + +`RET' +`e' + Edit/Open the current group or tag. This behavior is dependent on + the mode. In general, files or buffers are opened in the attached + frame, and directories or group nodes are expanded locally. + +`+' +`=' + Expand the current group, displaying sub items. When used with a + prefix argument, any data that may have been cached is flushed. + This is similar to a power click. *Note Mouse Bindings::. + +`-' + Contract the current group, hiding sub items. + + +File: speedbar.info, Node: Basic Visuals, Next: Mouse Bindings, Prev: Basic Key Bindings, Up: Basic Navigation + +Basic Visuals +============= + +Speedbar has visual cues for indicating different types of data. These +cues are used consistently across the different speedbar modes to make +them easier to interpret. + + At a high level, in File mode, there are directory buttons, sub +directory buttons, file buttons, tag buttons, and expansion buttons. +This makes it easy to use the mouse to navigate a directory tree, and +quickly view files, or a summary of those files. + + The most basic visual effect used to distinguish between these button +types is color and mouse highlighting. Anything the mouse highlights +can be clicked on and is called a button (*note Mouse Bindings::). +Anything not highlighted by the mouse will not be clickable. + + Text in speedbar consists of four different types of data. Knowing +how to read these textual elements will make it easier to navigate by +identifying the types of data available. + +Groups +...... + +Groups summarize information in a single line, and provide a high level +view of more complex systems, like a directory tree, or manual chapters. + + Groups appear at different indentation levels, and are prefixed with +a `+' in some sort of `box'. The group name will summarize the +information within it, and the expansion box will display that +information inline. In File mode, directories and files are `groups' +where the `+' is surrounded by brackets like this: + + <+> include + <-> src + [+] foo.c + + In this example, we see both open and closed directories, in +addition to a file. The directories have a box consisting of angle +brackets, and a file uses square brackets. + + In all modes, a group can be `edited' by pressing `RET', meaning a +file will be opened, or a directory explicitly opened in speedbar. A +group can be expanded or contracted using `+' or `-'. *Note Basic Key +Bindings::. + + Sometimes groups may have a `?' in its indicator box. This means +that it is a group type, but there are no contents, or no known way of +extracting contents of that group. + + When a group has been expanded, the indicator button changes from +`+' to `-'. This indicates that the contents are being shown. Click +the `-' button to contract the group, or hide the contents currently +displayed. + +Tags +.... + +Tags are the leaf nodes of the tree system. Tags are generally prefixed +with a simple character, such as `>'. Tags can only be jumped to using +`RET' or `e'. + +Boolean Flags +............. + +Sometimes a group or tag is given a boolean flag. These flags appear as +extra text characters at the end of the line. File mode uses boolean +flags, such as a `*' to indicate that a file has been checked out of a +versioning system. + + For additional flags, see *Note File Mode::, and *Note Version +Control::. + +Unadorned Text +.............. + +Unadorned text generally starts in column 0, without any special symbols +prefixing them. In Buffers mode different buffer groups are prefixed +with a description of what the following buffers are (Files, scratch +buffers, and invisible buffers.) + + Unadorned text will generally be colorless, and not clickable. + +Color Cues +.......... + +Each type of Group, item indicator, and label is given a different +color. The colors chosen are dependent on whether the background color +is light or dark. Of important note is that the `current item', which +may be a buffer or file name, is highlighted red, and underlined. + + Colors can be customized from the group `speedbar-faces'. Some +modes, such as for Info, will use the Info colors instead of default +speedbar colors as an indication of what is currently being displayed. + + The face naming convention mirrors the File display mode. Modes +which do not use files will attempt to use the same colors on analogous +entries. + + +File: speedbar.info, Node: Mouse Bindings, Next: Displays Submenu, Prev: Basic Visuals, Up: Basic Navigation + +Mouse Bindings +============== + +The mouse has become a common information navigation tool. Speedbar +will use the mouse to navigate file systems, buffer lists, and other +data. The different textual cues provide buttons which can be clicked +on (*note Basic Visuals::). Anything that highlights can be clicked on +with the mouse, or affected by the menu. + + The mouse bindings are: + +`Mouse-1' + Move cursor to that location. + +`Mouse-2' +`Double-Mouse-1' + Activate the current button. `Double-Mouse-1' is called a "double + click" on other platforms, and is useful for windows users with two + button mice. + +`S-Mouse-2' +`S-Double-Mouse-1' + This has the same effect as `Mouse-2', except it is called a power + click. This means that if a group with an expansion button `+' is + clicked, any caches are flushed, and subitems re-read. If it is a + name, it will be opened in a new frame. + +`Mouse-3' + Activate the speedbar menu. The item selected affects the line + clicked, not the line where the cursor was. + +`Mouse-1 (mode line)' + Activate the menu. This affects the item the cursor is on before + the click, since the mouse was not clicked on anything. + +`C-Mouse-1' + Buffers sub-menu. The buffer in the attached frame is switched. + + When the mouse moves over buttons in speedbar, details of that item +should be displayed in the minibuffer of the attached frame. Sometimes +this can contain extra information such as file permissions, or tag +location. + + +File: speedbar.info, Node: Displays Submenu, Prev: Mouse Bindings, Up: Basic Navigation + +Displays Submenu +================ + +You can display different data by using different display modes. These +specialized modes make it easier to navigate the relevant pieces of +information, such as files and directories, or buffers. + + In the main menu, found by clicking `Mouse-3', there is a submenu +labeled `Displays'. This submenu lets you easily choose between +different display modes. + + The contents are modes currently loaded into emacs. By default, this +would include Files, Quick Buffers, and Buffers. Other major display +modes such as Info are loaded separately. + + +File: speedbar.info, Node: File Mode, Next: Buffer Mode, Prev: Basic Navigation, Up: Top + +File Mode +********* + +File mode displays a summary of your current directory. You can display +files in the attached frame, or summarize the tags found in files. You +can even see if a file is checked out of a version control system, or +has some associated object file. + + Advanced behavior, like copying and renaming files, is also provided. + +* Menu: + +* Directory Display:: What the display means. +* Hidden Files:: How to display hidden files. +* File Key Bindings:: Performing file operations. + + +File: speedbar.info, Node: Directory Display, Next: Hidden Files, Prev: File Mode, Up: File Mode + +Directory Display +================= + +There are three major sections in the display. The first line or two is +the root directory speedbar is currently viewing. You can jump to one +of the parent directories by clicking on the name of the directory you +wish to jump to. + + Next, directories are listed. A directory starts with the group +indicator button `<+>'. Clicking the directory name makes speedbar +load that directory as the root directory for its display. Clicking the +`<+>' button will list all directories and files beneath. + + Next, files are listed. Files start with the group indicator `[+]' +or `[?]'. You can jump to a file in the attached frame by clicking on +the file name. You can expand a file and look at its tags by clicking +on the `[+]' symbol near the file name. + + A typical session might look like this: + + ~/lisp/ + <+> checkdoc + <+> eieio + <-> speedbar + [+] Makefile + [+] rpm.el # + [+] sb-gud.el # + [+] sb-info.el # + [+] sb-rmail.el # + [+] sb-w3.el + [-] speedbar.el *! + {+} Types + {+} Variables + {+} def (group) + {+} speedbar- + [+] speedbar.texi * + <+> testme + [+] align.el + [+] autoconf.el + + In this example, you can see several directories. The directory +`speedbar' has been opened inline. Inside the directory `speedbar', +the file `speedbar.el' has its tags exposed. These tags are extensive, +and they are summarized into tag groups. + + Files get additional boolean flags associated with them. Valid +flags are: + +`*' + This file has been checked out of a version control system. *Note + Version Control::. + +`#' + This file has an up to date object file associated with it. The + variable `speedbar-obj-alist' defines how speedbar determines this + value. + +`!' + This file has an out of date object file associated with it. + + A Tag group is prefixed with the symbol `{+}'. Clicking this symbol +will show all symbols that have been organized into that group. +Different types of files have unique tagging methods as defined by their +major mode. Tags are generated with either the `imenu' package, or +through the `etags' interface. + + Tag groups are defined in multiple ways which make it easier to find +the tag you are looking for. Imenu keywords explicitly create groups, +and speedbar will automatically create groups if tag lists are too long. + + In our example, Imenu created the groups `Types' and `Variables'. +All remaining top-level symbols are then regrouped based on the +variable `speedbar-tag-hierarchy-method'. The subgroups `def' and +`speedbar-' are groupings where the first few characters of the given +symbols are specified in the group name. Some group names may say +something like `speedbar-t to speedbar-v', indicating that all symbols +which alphabetically fall between those categories are included in that +sub-group. *Note Tag Hierarchy Methods::. + + +File: speedbar.info, Node: Hidden Files, Next: File Key Bindings, Prev: Directory Display, Up: File Mode + +Hidden Files +============ + +On GNU and Unix systems, a hidden file is a file whose name starts with +a period. They are hidden from a regular directory listing because the +user is not generally interested in them. + + In speedbar, a hidden file is a file which isn't very interesting and +might prove distracting to the user. Any uninteresting files are +removed from the File display. There are two levels of uninterest in +speedbar. The first level of uninterest are files which have no +expansion method, or way of extracting tags. You can define which +files are interesting with `speedbar-supported-extension-expressions'. +The second level is any file that matches the same pattern used for +completion in `find-file'. This is derived from the variable +`completion-ignored-extensions'. This filter will override the +supported extensions, so beif you add something to be supported, and it +doesn't appear, check for this. + + You can toggle the display of uninteresting files from the toggle +menu item `Show All Files'. This will display all level one hidden +files. These files will be shown with a `?' indicator. Level 2 hidden +files will still not be shown. + + Object files fall into the category of level 2 hidden files. You can +determine their presence by the `#' and `!' file indicators. *Note +Directory Display::. + + +File: speedbar.info, Node: File Key Bindings, Prev: Hidden Files, Up: File Mode + +File Key Bindings +================= + +File mode has key bindings permitting different file system operations +such as copy or rename. These commands all operate on the "current +file". In this case, the current file is the file at point, or clicked +on when pulling up the menu. + +`U' + Move the entire speedbar display up one directory. + +`I' + Display information in the minibuffer about this line. This is + the same information shown when navigating with `n' and `p', or + moving the mouse over an item. + +`B' + Byte compile the Emacs Lisp file on this line. + +`L' + Load the Emacs Lisp file on this line. If a `.elc' file exists, + optionally load that. + +`C' + Copy the current file to some other location. + +`R' + Rename the current file, possibly moving it to some other location. + +`D' + Delete the current file. + +`O' + Delete the current file's object file. Use the symbols `#' and + `!' to determine if there is an object file available. + + One menu item toggles the display of all available files. By +default, only files which Emacs understands, and knows how to convert +into a tag list, are shown. By showing all files, additional files +such as text files are also displayed, but they are prefixed with the +`[?]' symbol. This means that it is a file, but Emacs doesn't know how +to expand it. + + +File: speedbar.info, Node: Buffer Mode, Next: Minor Modes, Prev: File Mode, Up: Top + +Buffer Mode +*********** + +Buffer mode is very similar to File mode, except that instead of +tracking the current directory and all files available there, the +current list of Emacs buffers is shown. + + These buffers can have their tags expanded in the same way as files, +and uses the same unknown file indicator (*note File Mode::). + + Buffer mode does not have file operation bindings, but the following +buffer specific key bindings are available: + +`k' + Kill this buffer. Do not touch its file. + +`r' + Revert this buffer, reloading from disk. + + In addition to Buffer mode, there is also Quick Buffer mode. In +fact, Quick Buffers is bound to the `b' key. The only difference +between Buffers and Quick Buffers is that after one operation is +performed which affects the attached frame, the display is immediately +reverted to the last displayed mode. + + Thus, if you are in File mode, and you need quick access to a buffer, +press `b', click on the buffer you want, and speedbar will revert back +to File mode. + + +File: speedbar.info, Node: Minor Modes, Next: Customizing, Prev: Buffer Mode, Up: Top + +Minor Display Modes +******************* + +For some buffers, a list of files and tags makes no sense. This could +be because files are not currently in reference (such as web pages), or +that the files you might be interested have special properties (such as +email folders.) + + In these cases, a minor display mode is needed. A minor display mode +will override any major display mode currently being displayed for the +duration of the specialized buffer's use. Minor display modes will +follow the general rules of their major counterparts in terms of key +bindings and visuals, but will have specialized behaviors. + +* Menu: + +* RMAIL:: Managing folders in speedbar +* Info:: Browsing topics in speedbar +* GDB:: Managing the current stack trace in speedbar + + +File: speedbar.info, Node: RMAIL, Next: Info, Prev: Minor Modes, Up: Minor Modes + +RMAIL +===== + +When using RMAIL, speedbar will display two sections. The first is a +layer one reply button. Clicking here will initialize a reply buffer +showing only this email address in the `To:' field. + + The second section lists all RMAIL folders in the same directory as +your main RMAIL folder. The general rule is that RMAIL folders always +appear in all caps, or numbers. It is possible to save mail in folders +with lower case letters, but there is no clean way of detecting such +RMAIL folders without opening them all. + + Each folder can be visited by clicking the name. You can move mail +from the current RMAIL folder into a different folder by clicking the +`' button. The `M' stands for Move. + + In this way you can manage your existing RMAIL folders fairly easily +using the mouse. + + +File: speedbar.info, Node: Info, Next: GDB, Prev: RMAIL, Up: Minor Modes + +Info +==== + +When browsing Info files, all local relevant information is displayed in +the info buffer and a topical high-level view is provided in speedbar. +All top-level info nodes are shown in the speedbar frame, and can be +jumped to by clicking the name. + + You can open these nodes with the `[+]' button to see what sub-topics +are available. Since these sub-topics are not examined until you click +the `[+]' button, sometimes a `[?]' will appear when you click on a +`[+]', indicating that there are no sub-topics. + + +File: speedbar.info, Node: GDB, Prev: Info, Up: Minor Modes + +GDB +=== + +If you are debugging an application with GDB in Emacs, speedbar can show +you the current stack when the current buffer is the `*gdb*' buffer. +Usually, it will just report that there is no stack, but when the +application is stopped, the current stack will be shown. + + You can click on any stack element and gdb will move to that stack +level. You can then check variables local to that level at the GDB +prompt. + + This mode has the unfortunate side-effect of breaking GDB's repeat +feature when you hit `RET' since your previous command is overridden +with a stack fetching command. + + +File: speedbar.info, Node: Customizing, Next: Extending, Prev: Minor Modes, Up: Top + +Customizing +*********** + +Speedbar is highly customizable, with a plethora of control elements. +Since speedbar is so visual and reduces so much information, this is an +important aspect of its behavior. + + In general, there are three custom groups you can use to quickly +modify speedbar's behavior. + +`speedbar' + Basic speedbar behaviors. + +`speedbar-vc' + Customizations regarding version control handling. + +`speedbar-faces' + Customize speedbar's many colors and fonts. + +* Menu: + +* Frames and Faces:: Visible behaviors. +* Tag Hierarchy Methods:: Customizing how tags are displayed. +* Version Control:: Adding new VC detection modes. +* Hooks:: The many hooks you can use. + + +File: speedbar.info, Node: Frames and Faces, Next: Tag Hierarchy Methods, Prev: Customizing, Up: Customizing + +Frames and Faces +================ + +There are several faces speedbar generates to provide a consistent +color scheme across display types. You can customize these faces using +your favorite method. They are: + +speedbar-button-face + Face used on expand/contract buttons. + +speedbar-file-face + Face used on Files. Should also be used on non-directory like + nodes. + +speedbar-directory-face + Face used for directories, or nodes which consist of groups of + other nodes. + +speedbar-tag-face + Face used for tags in a file, or for leaf items. + +speedbar-selected-face + Face used to highlight the selected item. This would be the + current file being edited. + +speedbar-highlight-face + Face used when the mouse passes over a button. + + You can also customize speedbar's initial frame parameters. How +this is accomplished is dependent on your platform being Emacs or +XEmacs. + + In Emacs, change the alist `speedbar-frame-parameters'. This +variable is used to set up initial details. Height is also +automatically added when speedbar is created, though you can override +it. + + In XEmacs, change the plist `speedbar-frame-plist'. This is the +XEmacs way of doing the same thing. + + +File: speedbar.info, Node: Tag Hierarchy Methods, Next: Version Control, Prev: Frames and Faces, Up: Customizing + +Tag Hierarchy Methods +===================== + +When listing tags within a file, it is possible to get an annoyingly +long list of entries. Imenu (which generates the tag list in Emacs) +will group some classes of items automatically. Even here, however, +some tag groups can be quite large. + + To solve this problem, tags can be grouped into logical units +through a hierarchy processor. The specific variable to use is +`speedbar-tag-hierarchy-method'. There are several methods that can be +applied in any order. They are: + +`speedbar-trim-words-tag-hierarchy' + Find a common prefix for all elements of a group, and trim it off. + +`speedbar-prefix-group-tag-hierarchy' + If a group is too large, place sets of tags into bins based on + common prefixes. + +`speedbar-simple-group-tag-hierarchy' + Take all items in the top level list not in a group, and stick + them into a `Tags' group. + +`speedbar-sort-tag-hierarchy' + Sort all items, leaving groups on top. + + You can also add your own functions to reorganize tags as you see +fit. + + Some other control variables are: + +`speedbar-tag-group-name-minimum-length' + Default value: 4. + + The minimum length of a prefix group name before expanding. Thus, + if the `speedbar-tag-hierarchy-method' includes + `speedbar-prefix-group-tag-hierarchy' and one such group's common + characters is less than this number of characters, then the group + name will be changed to the form of: + + worda to wordb + + instead of just + + word + + This way we won't get silly looking listings. + +`speedbar-tag-split-minimum-length' + Default value: 20. + + Minimum length before we stop trying to create sub-lists in tags. + This is used by all tag-hierarchy methods that break large lists + into sub-lists. + +`speedbar-tag-regroup-maximum-length' + Default value: 10. + + Maximum length of submenus that are regrouped. If the regrouping + option is used, then if two or more short subgroups are next to + each other, then they are combined until this number of items is + reached. + + +File: speedbar.info, Node: Version Control, Next: Hooks, Prev: Tag Hierarchy Methods, Up: Customizing + +Version Control +=============== + +When using the file mode in speedbar, information regarding a version +control system adds small details to the display. If a file is in a +version control system, and is "checked out" or "locked" locally, an +asterisk `*' appears at the end of the file name. In addition, the +directory name for Version Control systems are left out of the speedbar +display. + + You can easily add new version control systems into speedbar's +detection scheme. To make a directory "disappear" from the list, use +the variable `speedbar-directory-unshown-regexp'. + + Next, you need to write entries for two hooks. The first is +`speedbar-vc-path-enable-hook' which will enable a VC check in the +current directory for the group of files being checked. Your hook +function should take one parameter (the directory to check) and return +`t' if your VC method is in control here. + + The second function is `speedbar-vc-in-control-hook'. This hook +takes two parameters, the PATH of the file to check, and the FILE name. +Return `t' if you want to have the asterisk placed near this file. + + Lastly, you can change the VC indicator using the variable +`speedbar-vc-indicator', and specify a single character string. + + +File: speedbar.info, Node: Hooks, Prev: Version Control, Up: Customizing + +Hooks +===== + +There are several hooks in speedbar allowing custom behaviors to be +added. Available hooks are: + +`speedbar-visiting-file-hook' + Hooks run when speedbar visits a file in the selected frame. + +`speedbar-visiting-tag-hook' + Hooks run when speedbar visits a tag in the selected frame. + +`speedbar-load-hook' + Hooks run when speedbar is loaded. + +`speedbar-reconfigure-keymaps-hook' + Hooks run when the keymaps are regenerated. Keymaps are + reconfigured whenever modes change. This will let you add custom + key bindings. + +`speedbar-before-popup-hook' + Hooks called before popping up the speedbar frame. New frames are + often popped up when "power clicking" on an item to view it. + +`speedbar-before-delete-hook' + Hooks called before deleting or hiding the speedbar frame. + +`speedbar-mode-hook' + Hooks called after creating a speedbar buffer. + +`speedbar-timer-hook' + Hooks called after running the speedbar timer function. + +`speedbar-scanner-reset-hook' + Hook called whenever generic scanners are reset. Set this to + implement your own scanning or rescan safe functions with state + data. + + +File: speedbar.info, Node: Extending, Next: Index, Prev: Customizing, Up: Top + +Extending +********* + +Speedbar can run different types of Major display modes such as Files +(*note File Mode::), and Buffers (*note Buffer Mode::). It can also +manage different minor display modes for use with buffers handling +specialized data. + + These major and minor display modes are handled through an extension +system which permits specialized keymaps and menu extensions, in +addition to a unique rendering function. You can also specify a wide +range of tagging functions. The default uses `imenu', but new tagging +methods can be easily added. In this chapter, you will learn how to +write your own major or minor display modes, and how to create +specialized tagging functions. + +* Menu: + +* Minor Display Modes:: How to create a minor display mode. +* Major Display Modes:: How to create a major display mode. +* Tagging Extensions:: How to create your own tagging methods. +* Creating a display:: How to insert buttons and hierarchies. + + +File: speedbar.info, Node: Minor Display Modes, Next: Major Display Modes, Prev: Extending, Up: Extending + +Minor Display Modes +=================== + +A "minor display mode" is a mode useful when using a specific type of +buffer. This mode might not be useful for any other kind of data or +mode, or may just be more useful that a files or buffers based mode when +working with a specialized mode. + + Examples that already exist for speedbar include RMAIL, Info, and +gdb. These modes display information specific to the major mode shown +in the attached frame. + + To enable a minor display mode in your favorite Major mode, follow +these steps. The string `NAME' is the name of the major mode being +augmented with speedbar. + + 1. Create the keymap variable `NAME-speedbar-key-map'. + + 2. Create a function, named whatever you like, which assigns values + into your keymap. Use this command to create the keymap before + assigning bindings: + + (setq NAME-speedbar-key-map (speedbar-make-specialized-keymap)) + + This function creates a special keymap for use in speedbar. + + 3. Call your install function, or assign it to a hook like this: + + (if (featurep 'speedbar) + (NAME-install-speedbar-variables) + (add-hook 'speedbar-load-hook 'NAME-install-speedbar-variables)) + + 4. Create an easymenu compatible vector named + `NAME-speedbar-menu-items'. This will be spliced into speedbar's + control menu. + + 5. Create a function called `NAME-speedbar-buttons'. This function + should take one variable, which is the buffer for which it will + create buttons. At this time `(current-buffer)' will point to the + uncleared speedbar buffer. + + When writing `NAME-speedbar-buttons', the first thing you will want +to do is execute a check to see if you need to re-create your display. +If it needs to be cleared, you need to erase the speedbar buffer +yourself, and start drawing buttons. *Note Creating a display::. + + +File: speedbar.info, Node: Major Display Modes, Next: Tagging Extensions, Prev: Minor Display Modes, Up: Extending + +Major Display Modes +=================== + +Creating a "Major Display Mode" for speedbar requires authoring a +keymap, an easy-menu segment, and writing several functions. These +items can be given any name, and are made the same way as in a minor +display mode (*note Minor Display Modes::). Once this is done, these +items need to be registered. + + Because this setup activity may or may not have speedbar available +when it is being loaded, it is necessary to create an install function. +This function should create and initialize the keymap, and add your +expansions into the customization tables. + + When creating the keymap, use the function +`speedbar-make-specialized-keymap' instead of other keymap making +functions. This will provide you with the initial bindings needed. +Some common speedbar functions you might want to bind are: + +`speedbar-edit-line' + Edit the item on the current line. + +`speedbar-expand-line' + Expand the item under the cursor. With a numeric argument + (`C-u'), flush cached data before expanding. + +`speedbar-contract-line' + Contract the item under the cursor. + + These function require that function `speedbar-line-path' be +correctly overloaded to work. + + Next, register your extension like this; + + (speedbar-add-expansion-list '("MyExtension" + MyExtension-speedbar-menu-items + MyExtension-speedbar-key-map + MyExtension-speedbar-buttons)) + + There are no limitations to the names you use. + + The first parameter is the string representing your display mode. +The second parameter is a variable name containing an easymenu +compatible menu definition. This will be stuck in the middle of +speedbar's menu. The third parameter is the variable name containing +the keymap we discussed earlier. The last parameter is a function +which draws buttons for your mode. This function must take two +parameters. The directory currently being displayed, and the depth at +which you should start rendering buttons. The function will then draw +(starting at the current cursor position) any buttons deemed necessary +based on the input parameters. *Note Creating a display::. + + Next, you need to register function overrides. This may look +something like this: + + (speedbar-add-mode-functions-list + '("MYEXTENSION" + (speedbar-item-info . MyExtension-speedbar-item-info) + (speedbar-line-path . MyExtension-speedbar-line-path))) + + The first element in the list is the name of you extension. The +second is an alist of functions to overload. The function to overload +is first, followed by what you want called instead. + + For `speedbar-line-path' your function should take an optional DEPTH +parameter. This is the starting depth for heavily indented lines. If +it is not provided, you can derive it like this: + + (save-match-data + (if (not depth) + (progn + (beginning-of-line) + (looking-at "^\\([0-9]+\\):") + (setq depth (string-to-int (match-string 1))))) + +where the depth is stored as invisible text at the beginning of each +line. + + The path returned should be the full path name of the file associated +with that line. If the cursor is on a tag, then the file containing +that tag should be returned. This is critical for built in file based +functions to work (meaning less code for you to write). If your display +does not deal in files, you do not need to overload this function. + + The function `speedbar-item-info', however, is very likely to need +overloading. This function takes no parameters and must derive a text +summary to display in the minibuffer. + + There are several helper functions you can use if you are going to +use built in tagging. These functions can be `or'ed since each one +returns non-nil if it displays a message. They are: + +`speedbar-item-info-file-helper' + This takes an optional FILENAME parameter. You can derive your own + filename, or it will derive it using a (possibly overloaded) + function `speedbar-line-file'. It shows details about a file. + +`speedbar-item-info-tag-helper' + If the current line is a tag, then display information about that + tag, such as its parent file, and location. + + Your custom function might look like this: + + (defun MyExtension-item-info () + "Display information about the current line." + (or (speedbar-item-info-tag-helper) + (message "Interesting detail."))) + + Once you have done all this, speedbar will show an entry in the +`Displays' menu declaring that your extension is available. + + +File: speedbar.info, Node: Tagging Extensions, Next: Creating a display, Prev: Major Display Modes, Up: Extending + +Tagging Extensions +================== + +It is possible to create new methods for tagging files in speedbar. To +do this, you need two basic functions, one function to fetch the tags +from a buffer, the other to insert them below the filename. + + - Function: my-fetch-dynamic-tags file + Parse FILE for a list of tags. Return the list, or `t' if there + was an error. FILE is not necessarily available as an buffer when + your function is called. Be sure to load it if it is needed with + code like this: + + (save-excursion + (set-buffer (find-file-noselect file)) + ... + ) + + The non-error return value can be anything, as long as it can be +inserted by its paired function: + + - Function: my-insert-tag-list level lst + Insert a list of tags LST started at indentation level LEVEL. + Creates buttons for each tag, and provides any other display + information required. + + It is often useful to use `speedbar-create-tag-hierarchy' on your +token list. See that function's documentation for details on what it +requires. + + Once these two functions are written, modify the variable +`speedbar-dynamic-tags-function-list' to include your parser at the +beginning, like this: + + (add-to-list 'speedbar-dynamic-tags-function-list + '(my-fetch-dynamic-tags . my-insert-tag-list)) + + If your parser is only good for a few types of files, make sure that +it is either a buffer local modification, or that the tag generator +returns `t' for non valid buffers. + + +File: speedbar.info, Node: Creating a display, Prev: Tagging Extensions, Up: Extending + +Creating a display +================== + +Rendering a display in speedbar is completely flexible. When your +button function is called, see *Note Minor Display Modes::, and *Note +Major Display Modes::, you have control to `insert' anything you want. + + The conventions allow almost anything to be inserted, but several +helper functions are provided to make it easy to create the standardized +buttons. + + To understand the built in functions, each `button' in speedbar +consists of four important pieces of data. The text to be displayed, +token data to be associated with the text, a function to call, and some +face to display it in. + + When a function is provided, then that text becomes mouse activated, +meaning the mouse will highlight the text. + + Additionally, for data which can form deep trees, each line is given +a depth which indicates how far down the tree it is. This information +is stored in invisible text at the beginning of each line, and is used +by the navigation commands. + + - Function: speedbar-insert-button text face mouse function &optional + token prevline + This function inserts one button into the current location. TEXT + is the text to insert. FACE is the face in which it will be + displayed. MOUSE is the face to display over the text when the + mouse passes over it. FUNCTION is called whenever the user clicks + on the text. + + The optional argument TOKEN is extra data to associated with the + text. Lastly PREVLINE should be non-nil if you want this line to + appear directly after the last button which was created instead of + on the next line. + + - Function: speedbar-make-tag-line exp-button-type exp-button-char + exp-button-function exp-button-data tag-button + tag-button-function tag-button-data tag-button-face depth + Create a tag line with EXP-BUTTON-TYPE for the small expansion + button. This is the button that expands or contracts a node (if + applicable), and EXP-BUTTON-CHAR the character in it (`+', `-', + `?', etc). EXP-BUTTON-FUNCTION is the function to call if it's + clicked on. Button types are `'bracket', `'angle', `'curly', + `'expandtag', `'statictag', or nil. EXP-BUTTON-DATA is extra data + attached to the text forming the expansion button. + + Next, TAG-BUTTON is the text of the tag. TAG-BUTTON-FUNCTION is + the function to call if clicked on, and TAG-BUTTON-DATA is the + data to attach to the text field (such a tag positioning, etc). + TAG-BUTTON-FACE is a face used for this type of tag. + + Lastly, DEPTH shows the depth of expansion. + + This function assumes that the cursor is in the speedbar window at + the position to insert a new item, and that the new item will end + with a CR. + + - Function: speedbar-insert-generic-list level list expand-fun find-fun + At LEVEL, (the current indentation level desired) insert a generic + multi-level alist LIST. Associations with lists get `{+}' tags + (to expand into more nodes) and those with positions or other data + just get a `>' as the indicator. `{+}' buttons will have the + function EXPAND-FUN and the token is the `cdr' list. The token + name will have the function FIND-FUN and not token. + + Each element of the list can have one of these forms: + + `(NAME . marker-or-number)' + One tag at this level. + + `(NAME (NAME . marker-or-number) (NAME . marker-or-number) ... )' + One group of tags. + + `(NAME marker-or-number (NAME . marker-or-number) ... )' + One Group of tags where the group has a starting position. + + When you use `speedbar-insert-generic-list', there are some + variables you can set buffer-locally to change the behavior. The + most obvious is `speedbar-tag-hierarchy-method'. *Note Tag + Hierarchy Methods::. + + - Variable: speedbar-generic-list-group-expand-button-type + This is the button type used for groups of tags, whether + expanded or added in via a hierarchy method. Two good values + are `'curly' and `'expandtag'. Curly is the default button, + and `'expandtag' is useful if the groups also has a position. + + - Variable: speedbar-generic-list-tag-button-type + This is the button type used for a single tag. Two good + values are `nil' and `'statictag'. `nil' is the default, and + `'statictag' has the same width as `'expandtag'. + + + +File: speedbar.info, Node: Index, Prev: Extending, Up: Top + +Concept Index +************* + +* Menu: + +* buffer mode: Buffer Mode. +* common keys: Basic Key Bindings. +* create major display mode: Major Display Modes. +* create minor display mode: Minor Display Modes. +* creating a display: Creating a display. +* customizing: Customizing. +* directory display: Directory Display. +* displays submenu: Displays Submenu. +* extending: Extending. +* faces: Frames and Faces. +* file flags: Directory Display. +* file key bindings: File Key Bindings. +* file mode: File Mode. +* frame parameters: Frames and Faces. +* gdb: GDB. +* groups: Basic Visuals. +* gud: GDB. +* hidden files: Hidden Files. +* hooks: Hooks. +* Info: Info. +* introduction: Introduction. +* key bindings: Basic Key Bindings. +* minor display modes: Minor Modes. +* mode switching hotkeys: Basic Key Bindings. +* mouse bindings: Mouse Bindings. +* my-fetch-dynamic-tags: Tagging Extensions. +* my-insert-tag-list: Tagging Extensions. +* navigation: Basic Key Bindings. +* power click: Mouse Bindings. +* quitting speedbar: Basic Key Bindings. +* refresh speedbar display: Basic Key Bindings. +* RMAIL: RMAIL. +* scrolling in speedbar: Basic Key Bindings. +* slowbar mode: Basic Key Bindings. +* speedbar-before-delete-hook: Hooks. +* speedbar-before-popup-hook: Hooks. +* speedbar-button-face: Frames and Faces. +* speedbar-contract-line: Major Display Modes. +* speedbar-create-tag-hierarchy: Tagging Extensions. +* speedbar-directory-face: Frames and Faces. +* speedbar-directory-unshown-regexp: Version Control. +* speedbar-dynamic-tags-function-list: Tagging Extensions. +* speedbar-edit-line: Major Display Modes. +* speedbar-expand-line: Major Display Modes. +* speedbar-file-face: Frames and Faces. +* speedbar-frame-parameters, Emacs: Frames and Faces. +* speedbar-frame-plist, XEmacs: Frames and Faces. +* speedbar-get-focus: Introduction. +* speedbar-highlight-face: Frames and Faces. +* speedbar-insert-button: Creating a display. +* speedbar-insert-generic-list: Creating a display. +* speedbar-item-info: Major Display Modes. +* speedbar-item-info-file-helper: Major Display Modes. +* speedbar-item-info-tag-helper: Major Display Modes. +* speedbar-line-path: Major Display Modes. +* speedbar-load-hook: Hooks. +* speedbar-make-specialized-keymap: Major Display Modes. +* speedbar-make-tag-line: Creating a display. +* speedbar-mode-hook: Hooks. +* speedbar-obj-alist: Directory Display. +* speedbar-prefix-group-tag-hierarchy: Tag Hierarchy Methods. +* speedbar-reconfigure-keymaps-hook: Hooks. +* speedbar-scanner-reset-hook: Hooks. +* speedbar-selected-face: Frames and Faces. +* speedbar-simple-group-tag-hierarchy: Tag Hierarchy Methods. +* speedbar-sort-tag-hierarchy: Tag Hierarchy Methods. +* speedbar-tag-face: Frames and Faces. +* speedbar-tag-group-name-minimum-length: Tag Hierarchy Methods. +* speedbar-tag-hierarchy-method: Tag Hierarchy Methods. +* speedbar-tag-regroup-maximum-length: Tag Hierarchy Methods. +* speedbar-tag-split-minimum-length: Tag Hierarchy Methods. +* speedbar-timer-hook: Hooks. +* speedbar-trim-words-tag-hierarchy: Tag Hierarchy Methods. +* speedbar-vc-in-control-hook: Version Control. +* speedbar-vc-indicator: Version Control. +* speedbar-vc-path-enable-hook: Version Control. +* speedbar-visiting-file-hook: Hooks. +* speedbar-visiting-tag-hook: Hooks. +* tag groups: Tag Hierarchy Methods. +* tag hierarchy: Tag Hierarchy Methods. +* tag sorting: Tag Hierarchy Methods. +* tags: Basic Visuals. +* vc extensions: Version Control. +* version control: Version Control. +* visuals: Basic Visuals. + + + +Tag Table: +Node: Top1260 +Node: Introduction3042 +Node: Basic Navigation4602 +Node: Basic Key Bindings5043 +Node: Basic Visuals7225 +Node: Mouse Bindings11092 +Node: Displays Submenu12709 +Node: File Mode13381 +Node: Directory Display13984 +Node: Hidden Files17014 +Node: File Key Bindings18455 +Node: Buffer Mode19881 +Node: Minor Modes20992 +Node: RMAIL21844 +Node: Info22734 +Node: GDB23333 +Node: Customizing23992 +Node: Frames and Faces24799 +Node: Tag Hierarchy Methods26119 +Node: Version Control28331 +Node: Hooks29665 +Node: Extending30897 +Node: Minor Display Modes31939 +Node: Major Display Modes33922 +Node: Tagging Extensions38681 +Node: Creating a display40325 +Node: Index44851 + +End Tag Table diff --git a/xemacs-packages/info/tempo.info b/xemacs-packages/info/tempo.info new file mode 100644 index 00000000..adc5f8f8 --- /dev/null +++ b/xemacs-packages/info/tempo.info @@ -0,0 +1,588 @@ +This is tempo.info, produced by makeinfo version 4.7 from tempo.texi. + + This is Edition 0.0(prerelease), last updated 8 June 1995, of `the +Tempo manual', for `tempo.el' version 1.2.3. + + Copyright (C) 1995 David Kågedal + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +that the section entitled "Copying"is included exactly as in the +original, and provided that the entire resulting derived work is +distributed under the terms of a permission notice identical to this +one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Free Software Foundation. + + +File: tempo.info, Node: Top, Next: Overview, Prev: (dir), Up: (dir) + +Tempo +***** + +This is Edition 0.0(prerelease), last updated 8 June 1995, of the +manual for `tempo.el' version 1.2.3. + + Tempo is a template writing package for GNU Emacs. + +* Menu: + +* Overview:: An overview of tempo +* Templates:: Templates +* Options:: Controlling tempo behaviour +* The mark list:: The mark list +* The save list:: The save list +* Adding tempo:: Adding tempo support +* Concept index:: Concept index +* Function index:: Function index +* Variable index:: Variable index +* Copying:: The terms of this distribution + + --- The Detailed Node Listing --- + +Overview + +* A short example:: Example +* Basics:: Tempo basics +* Tags overview:: Tag lists and automatic completion + +Templates + +* Syntax:: Template syntax +* Elements:: Template elements +* Defining your own elements:: Defining your own elements + + +File: tempo.info, Node: Overview, Next: Templates, Prev: Top, Up: Top + +1 Overview +********** + +Tempo is a package that provides writers and users of Emacs editing +modes with functions for creating and inserting templates into an Emacs +buffer in a convenient way. The template insertion commands can be bound +to keys or can be automatically expanded from words written in the +buffer. + +* Menu: + +* A short example:: Example +* Basics:: Tempo basics +* Tags overview:: Tag lists and automatic completion + + +File: tempo.info, Node: A short example, Next: Basics, Prev: Overview, Up: Overview + +1.1 A short example +=================== + +A good way to get a general idea of what `tempo' is about is through an +introductory example. The follwoing short example of a `tempo' template +builds a template for inserting a for loop in a C program. + + (tempo-define-template "c-for" + '("for (" + (p "Initialization: ") "," + (p "Increment: ") "," + (p "End condition: ") " {" n> + r n> + "}" > %)) + + This creates a command `tempo-template-c-for' which, when executed, +inserts the following at the point: + + for (-!-,,) { + + } + + The point is placed at the -!-, which is not included in the text. +The command `M-x tempo-forward-mark' will, at this point, move the +point to after the first comma. Successive executions will move the +point to after the second comma, to the second line and to after the +closing brace. In a mode customized for tempo, `tempo-forward-mark' +will of course be bound to some convenient keystroke combination. + + If the variable `tempo-interactive' was set to non-nil, the result +would have been a little different. Instead of inserting nothing inside +the parenthesis, the user would be prompted for the text to be written +in the three positions, with the prompt strings `Initialization:', +`Increment:' and `End condition:', respectively, and the point would be +placed on the second line, properly indented. + + Also, if there was a currently active region (*note Regions: +(emacs)Mark.), and the template command was used with a prefix argument +(such as `C-u M-x tempo-template-c-for') the for loop would be inserted +around the region, so that the contents of the region would be placed +between the the opening and closing braces. + + +File: tempo.info, Node: Basics, Next: Tags overview, Prev: A short example, Up: Overview + +1.2 Tempo basics +================ + +The most inportant function in tempo is `tempo-define-template', which +defines a template, together with a function to insert it. *Note +Syntax::, for a complete description of this function. + + A simple definition has the form + + (tempo-define-template NAME ELEMENTS) + + When this is evaluated, the variable `tempo-template-NAME' is bound +to ELEMENTS, and the function `tempo-template-NAME' is a command that +will insert the template when invoked. + + The ELEMENTS is supplied as a list whose elements have different +meanings. Strings are simply inserted and lisp expressions are evaluated +to strings. There are also some symbols with special meanings, such as: + +`p' +`(p PROMPT [NAME])' + The symbol `p' marks a "hot spot" in a template. When this is + encountered, the current position of the point is saved as a + marker and saved on the `tempo-marks' list. These marks can later + easily be jumped to with the functions `tempo-forward-mark' and + `tempo-backward-mark'. + + If the form `(p PROMPT)' is used, and the variable + `tempo-interactive' is non-`nil', PROMPT is used to prompt the + user for a string in the minibuffer. If `tempo-interactive' is + `nil', it works just like a single `p'. + +`r' +`(r PROMPT)' + This works very much like `p', but when the template was invoked + with a prefix (as with `C-u TEMPLATE-CMD') and a region is active, + the template will be wrapped around the region, so that the text + of the region is placed where the `r' element is. + +`>' + A greater-than sign in a template means that the current line + should be indented according to the current mode. The function + `indent-line' is called, which usually gives the desired result. + not that often it is advisable to insert the `>' after the text to + be put on the line, to help the indention function. + + + There are many more thing you can put in a template, but the above +are some of the more essential. *Note Elements::, for a full +description of the possible template elements. + + +File: tempo.info, Node: Tags overview, Prev: Basics, Up: Overview + +1.3 Tag lists and automatic completion +====================================== + +If you supply a third argument TAG to `tempo-define-template', it can +be used as an abbrevation for the template. If you gave the C for-loop +in the example above a third argument `"for"', you could use the +completion capabilities in tempo. If you write in a buffer (with the +point at -!-): + + for-!- + + and type `M-x tempo-complete-tag', the string `foo' would be +replaced by the for-loop template. For this to be really useful, +`tempo-complete-tag' should be bound to a convenient keystroke. But +there is more power in this command. If you have defined a template with +the tag `procedure' you can hit `M-x tempo-complete-tag' as soon as you +have written a unique prefix of the word. For example + + proc-!- + + could expand to + + procedure -!-(); + begin + + end; + + when you type `M-x tempo-complete-tag' had you defined a Pascal +`procedure' template with the tag `procedure'. If there is no unique +match, `tempo-complete-tag' will complete the tag as much as possible, +and show a buffer with the possible completions. You can then type +another character, which will hopefully make it unique and press `M-x +tempo-complete-tag' again. + + Unfortunaly, there is no good way to use the mouse in the completion +buffer, although it claims to be so. + + +File: tempo.info, Node: Templates, Next: Options, Prev: Overview, Up: Top + +2 Templates +*********** + +This node describes the syntax and semantics of templates defined by +`tempo-define-template'. The first part deals with the syntax of the +function itself, while the second part describes the different template +elements. + +* Menu: + +* Syntax:: Template syntax +* Elements:: Template elements +* Defining your own elements:: Defining your own elements + + +File: tempo.info, Node: Syntax, Next: Elements, Prev: Templates, Up: Templates + +2.1 Template syntax +=================== + +Templates are defined with the function `tempo-define-tempalate'. + + -- Function: tempo-define-template name elements [tag documentation + [taglist]]] + Define a template named `tempo-template-NAME'. + + This function creates a template and binds it to a new variable + named `tempo-template-NAME'. It also creates a new command under + the same name. This command expands the template at the current + point, when invoked. + + The parameter ELEMENTS is a list of template elements. The + possible elements are described in *Note Elements::. + + If a TAG is supplied, it must be a string which is placed in + TAGLIST or `tempo-tags'. This string is used for automatic + completion. When `tempo-complete-tag' is called and TAG is + matched, the template template defined with TAG is inserted. + (*note Tags overview:: for more information on tags and tag lists) + + +File: tempo.info, Node: Elements, Next: Defining your own elements, Prev: Syntax, Up: Templates + +2.2 Template elements +===================== + +These are the predefined elements you can use in a template definition: + +`STRING' + A string in a template is first run through the string + preprocessors in `tempo-insert-string-functions' and the result is + inserted. + +`p' + This denotes an "interesting" position in the template. When the + template is expanded, this position is remembered with a mark on + the tempo-marks list. *Note The mark list::. + +`r' + This works in a similar way to the above `p' element, but if the + template command is given a prefix command, the current region is + placed here. This means that the preceding part of the template is + expanded before the region, and the rest is expanded after. There + can be only one `r' in a template. If `transient-mark-mode' is + active (*note Regions: (emacs)Mark.) the current region is used + and the prefix argument is ignored. + + If the variable `tempo-insert-region' is non-nil, the behaviour of + the `r' element is reversed. + +`(p PROMPT [NAME [NOINSERT]])' +`(P PROMPT [NAME [NOINSERT]])' +`(r PROMPT [NAME [NOINSERT]])' + If the variable `tempo-interactive' is nil, the elements `(p + ...))' and `(P ...)' work exactly like a single `p', and `(r ...)' + works like a single `r'. + + But, if you set `tempo-interactive' to `t' the user is prompted + for a string to insert when the template is expanded. The prompt + is taken from the `prompt' parameter. The element `(P ...)' works + like `(p ...)' with the exception that `tempo-interactive' is + forced to `t', which means that the user will always (almost + always, see below) be prompted. + + If you provide a NAME to any of these, and interactive prompting + is taking place, the resulting string is saved in a local list so + it can be inserted again later with the `(s ...)' element. *Note + The save list::, for more detailed information. + + As a special case, if the save list already contains something + under NAME, it is used directly, and no prompting is done, even + with a `(P ...)' element. + + The third argument, NOINSERT, disables insertion of text. If + `tempo-interactive' it non-`nil', and a NAME has been provided, + normally a string is read through the minibuffer and then inserted + and saved. When NOINSERT is non-`nil', nothing is inserted, and + the text is only saved for later. + + Stylistic conventions (invented by me) dictates that these elements + should be placed as early as possible in template definitions. + +`r>' + This element works like `r', but it also indents the region it is + expanded around. + +`(s NAME)' + This looks up NAME in the save list and inserts what it finds. + Note that if it finds a string, it is not run through the string + preprocessors. + +`&' + An ampersand inserts a newline if there are characters other than + whitespace before the current point on the line. Otherwise it does + nothing. This means that it makes sure that the following text + always starts a new line, possibly with some leading whitespace. + +`%' + A percent sign inserts a newline it there are characters other than + whitespace after the current point on the line. Otherwise it does + nothing. + +`n' + Simply inserts a newline character. + +`>' + This does not insert any text. Instead it indents the line + according to the major mode, by calling + `indent-according-to-mode'. Note that in order to get best + results, you often should place this after the text you want to + place on the line, as this could affect the indentation. + +`n>' + Inserts a newline and indents line. It is the same as a `n' + followed by a `>'. + +`o' + Works like `%', but leaves the point on the first line. Note that + this can cause great confusion if you are not careful. If the `o' + is the first element in a template which is inserted at the + beginning of a line, strange things happen. This is due to odd + behaviour in `open-line'. + +`nil' + A `nil' element is simply igonred. That means that a lisp + expression (see below) that returns nil does not insert anything. + +`(l ELEMENT1 ELEMENT2...)' + This element is most useful as a return value from a lisp + expression (see below). It inserts the elements using the same + rules as all template elements. + +`Anything else' + All unrecognized elements are checked to see if it is a + user-defined elemet. *Note Defining your own elements::. If isn't, + it is assumed to be a lisp expression and is evaluated in a normal + fashion. The result from such an expression is taken as a template + element an is inserted according to the usual rules. If you don't + want to insert anything, make your expression return `nil'. If you + want to insert more than one element, use the `(l ELEMENT1 + ELEMENT2...)' element. + + + +File: tempo.info, Node: Defining your own elements, Prev: Elements, Up: Templates + +2.3 Defining your own elements +============================== + +The variable `tempo-user-elements' contains a list of functions to call +when an unrecognized element is found. + + -- Variable: tempo-user-elements + A list of functions. When `tempo-insert' is called with an element + it doesn't recognize, it checks this list by calling each function + with the element as the single argument. A function in this list + should take a single element as argument and return `nil' for + elements it doesn't recognize. If it does recognize an element, it + should return another element to be inserted, e.g. a string. If + the function wants to return an authorative `nil', it could return + either `""' or `(l)'. + + Do not use any one-charachter tags for your own elements. These are +reserved for future tempo enhancements. + + +File: tempo.info, Node: Options, Next: The mark list, Prev: Templates, Up: Top + +3 Controlling tempo behaviour +***************************** + +There are some options available for the end user of tempo templates. + + -- User Option: tempo-interactive + Controls whether templates should prompt the user for strings to + insert via the minibuffer or let the user edit them in place. This + affects the behaviour of the template elements `(p ...)' and `(r + ...)'. + + -- User Option: tempo-insert-region + Controls the behaviour of the `r', `r>' and `(r ...)' tags. If + this variable is `nil', `r' elements will be treated just like `p' + elements, unless the template command is given a prefix (or a + non-nil argument), in which case the template will be inserted + around the region. *Note Elements::, for further information. If + this variable is non-`nil', the behaviour is reversed. + + In Transient Mark mode, this option is unused. + + +File: tempo.info, Node: The mark list, Next: The save list, Prev: Options, Up: Top + +4 The mark list +*************** + +When a `p' or `r' element is inserted, or when `tempo-interactive' is +nil and a `(p ...)', `(P ...)' or `(r ...)' element is inserted, the +current position in the buffer is remembered for later. A mark is +created and stored in the variable `tepo-marks'. + + There are two functions for moving between these marks. + + -- Function: tempo-forward-mark + Move the point to the first mark on the mark list that is after the + point. If there is no such mark, nothing happens. + + -- Function: tempo-backward-mark + Move the point to the last mark on the mark lit that is before the + point. If there is no such mark, nothing happens. + + This function adds marks to the mark list. + + -- Function: tempo-insert-mark mark + Inserts MARK in the mark list, while keeping the list sorted. If + there already is a mark at the same position, only one mark is + kept. + + +File: tempo.info, Node: The save list, Next: Adding tempo, Prev: The mark list, Up: Top + +5 The save list +*************** + +In a template, different elements can be saved for later with the +function `tempo-save-named' on a data structure called the "save list". +The most obvious way to do this, is to supply a NAME argument to the +`(p ...)' element or one of its likes, but it can also be done +programmatically with an explicit call to `tempo-save-named'. + + Every saved element is saved in the list `tempo-named-insertions'. +After inserting a template, this list is cleared, so things saved in it +does not live between insertions. You should use ordinary variables for +that. + + The following two functions could be used from inside a template. + + -- Function: tempo-save-named name data + Save DATA on the save list under the name NAME. The function + returns nil. + + -- Function: tempo-lookup-named name + Lookup some saved data under the name NAME. Returns the data if + NAME was found, and `nil' otherwise. + + The following functions deal with the save list, but should be +considered internal to tempo. + + -- Function: tempo-insert-named name + Insert the previous insertion saved under a named specified in + NAME. If there is no such name saved, a tempo mark is inserted. + + Note that if the data is a string, it will not be run through the + string processor. + + -- Function: tempo-forget-insertions + Clears the save list. + + +File: tempo.info, Node: Adding tempo, Next: Concept index, Prev: The save list, Up: Top + +6 Adding tempo support +********************** + + +File: tempo.info, Node: Concept index, Next: Function index, Prev: Adding tempo, Up: Top + +7 Concept index +*************** + +[index] +* Menu: + +* Adding elements: Defining your own elements. + (line 6) +* Customization: Options. (line 6) +* Defining elements: Defining your own elements. + (line 6) +* Defining new templates: Syntax. (line 6) +* Elements: Elements. (line 6) +* Template elements: Elements. (line 6) +* Templates: Syntax. (line 6) +* User options: Options. (line 6) +* User-defined elements: Defining your own elements. + (line 6) +* Writing templates: Syntax. (line 6) + + +File: tempo.info, Node: Function index, Next: Variable index, Prev: Concept index, Up: Top + +8 Function index +**************** + +[index] +* Menu: + +* tempo-backward-mark: The mark list. (line 18) +* tempo-define-template: Syntax. (line 10) +* tempo-forget-insertions: The save list. (line 38) +* tempo-forward-mark: The mark list. (line 14) +* tempo-insert-mark: The mark list. (line 24) +* tempo-insert-named: The save list. (line 31) +* tempo-lookup-named: The save list. (line 24) +* tempo-save-named: The save list. (line 20) + + +File: tempo.info, Node: Variable index, Next: Copying, Prev: Function index, Up: Top + +9 Variable index +**************** + +[index] +* Menu: + +* tempo-insert-region: Options. (line 15) +* tempo-interactive: Options. (line 9) +* tempo-named-insertions: The save list. (line 12) +* tempo-user-elements: Defining your own elements. + (line 10) + + +File: tempo.info, Node: Copying, Prev: Variable index, Up: Top + +10 Copying +********** + + + +Tag Table: +Node: Top991 +Node: Overview2119 +Node: A short example2670 +Node: Basics4592 +Node: Tags overview6759 +Node: Templates8172 +Node: Syntax8666 +Node: Elements9695 +Node: Defining your own elements14723 +Node: Options15654 +Node: The mark list16628 +Node: The save list17624 +Node: Adding tempo19088 +Node: Concept index19230 +Node: Function index20318 +Node: Variable index21057 +Node: Copying21567 + +End Tag Table diff --git a/xemacs-packages/info/tramp.info b/xemacs-packages/info/tramp.info new file mode 100644 index 00000000..0f9bc84e --- /dev/null +++ b/xemacs-packages/info/tramp.info @@ -0,0 +1,2114 @@ +This is tramp.info, produced by makeinfo version 4.7 from tramp.texi. + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free +Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +INFO-DIR-SECTION XEmacs +START-INFO-DIR-ENTRY +* TRAMP: (tramp). Transparent Remote Access, Multiple Protocol + XEmacs remote file access via rsh and rcp. +END-INFO-DIR-ENTRY + + +File: tramp.info, Node: Top, Next: Overview, Prev: (dir), Up: (dir) + +TRAMP version 2.0.53 User Manual +******************************** + +This file documents TRAMP version 2.0.53, a remote file editing package +for XEmacs. + + TRAMP stands for `Transparent Remote (file) Access, Multiple +Protocol'. This package provides remote file editing, similar to +EFS. + + The difference is that EFS uses FTP to transfer files between the +local and the remote host, whereas TRAMP uses a combination of `rsh' +and `rcp' or other work-alike programs, such as `ssh'/`scp'. + + You can find the latest version of this document on the web at +`http://www.gnu.org/software/tramp/'. + + There is a mailing list for TRAMP, available at +, and archived at the TRAMP Mail Archive +(http://lists.gnu.org/archive/html/tramp-devel/). + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free +Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +* Menu: + +* Overview:: What TRAMP can and cannot do. + +For the end user: + +* Obtaining Tramp:: How to obtain TRAMP. +* History:: History of TRAMP. +* Configuration:: Configuring TRAMP for use. +* Usage:: An overview of the operation of TRAMP. +* Bug Reports:: Reporting Bugs and Problems. +* Frequently Asked Questions:: Questions and answers from the mailing list. +* Concept Index:: An item for each concept. + +For the developer: + +* Version Control:: The inner workings of remote version control. +* Files directories and localnames:: How file names, directories and localnames are mangled and managed. +* Issues:: Debatable Issues and What Was Decided. + + --- The Detailed Node Listing --- + +Configuring TRAMP for use + +* Connection types:: Types of connections made to remote machines. +* Inline methods:: Inline methods. +* External transfer methods:: External transfer methods. +* Multi-hop Methods:: Connecting to a remote host using multiple hops. +* Default Method:: Selecting a default method. +* Customizing Methods:: Using Non-Standard Methods. +* Customizing Completion:: Selecting config files for user/host name completion. +* Password caching:: Reusing passwords for several connections. +* Remote Programs:: How TRAMP finds and uses programs on the remote machine. +* Remote shell setup:: Remote shell setup hints. +* Windows setup hints:: Issues with Cygwin ssh. +* Auto-save and Backup:: Auto-save and Backup. + +Using TRAMP + +* Filename Syntax:: TRAMP filename conventions. +* Multi-hop filename syntax:: Multi-hop filename conventions. +* Filename completion:: Filename completion. +* Dired:: Dired. +* Compilation:: Compile remote files. + +The inner workings of remote version control + +* Version Controlled Files:: Determining if a file is under version control. +* Remote Commands:: Executing the version control commands on the remote machine. +* Changed workfiles:: Detecting if the working file has changed. +* Checking out files:: Bringing the workfile out of the repository. +* Miscellaneous Version Control:: Things related to Version Control that don't fit elsewhere. + +Things related to Version Control that don't fit elsewhere + +* Remote File Ownership:: How VC determines who owns a workfile. +* Back-end Versions:: How VC determines what release your RCS is. + +How file names, directories and localnames are mangled and managed + +* Localname deconstruction:: Breaking a localname into its components. + + +File: tramp.info, Node: Overview, Next: Obtaining Tramp, Prev: Top, Up: Top + +1 An overview of TRAMP +********************** + +After the installation of TRAMP into your XEmacs, you will be able to +access files on remote machines as though they were local. Access to +the remote file system for editing files, version control, and `dired' +are transparently enabled. + + Your access to the remote machine can be with the `rsh', `rlogin', +`telnet' programs or with any similar connection method. This +connection must pass ASCII successfully to be usable but need not be +8-bit clean. + + The package provides support for `ssh' connections out of the box, +one of the more common uses of the package. This allows relatively +secure access to machines, especially if `ftp' access is disabled. + + The majority of activity carried out by TRAMP requires only that the +remote login is possible and is carried out at the terminal. In order +to access remote files TRAMP needs to transfer their content to the +local machine temporarily. + + TRAMP can transfer files between the machines in a variety of ways. +The details are easy to select, depending on your needs and the +machines in question. + + The fastest transfer methods (for large files) rely on a remote file +transfer package such as `rcp', `scp' or `rsync'. + + If the remote copy methods are not suitable for you, TRAMP also +supports the use of encoded transfers directly through the shell. This +requires that the `mimencode' or `uuencode' tools are available on the +remote machine. These methods are generally faster for small files. + + Within these limitations, TRAMP is quite powerful. It is worth +noting that, as of the time of writing, it is far from a polished +end-user product. For a while yet you should expect to run into rough +edges and problems with the code now and then. + + It is finished enough that the developers use it for day to day work +but the installation and setup can be a little difficult to master, as +can the terminology. + + TRAMP is still under active development and any problems you +encounter, trivial or major, should be reported to the TRAMP developers. +*Note Bug Reports::. + +Behind the scenes +................. + +This section tries to explain what goes on behind the scenes when you +access a remote file through TRAMP. + + Suppose you type `C-x C-f' and enter part of an TRAMP file name, +then hit `' for completion. Suppose further that this is the +first time that TRAMP is invoked for the host in question. Here's what +happens: + + * TRAMP discovers that it needs a connection to the host. So it + invokes `telnet HOST' or `rsh HOST -l USER' or a similar tool to + connect to the remote host. Communication with this process + happens through an XEmacs buffer, that is, the output from the + remote end goes into a buffer. + + * The remote host may prompt for a login name (for `telnet'). The + login name is given in the file name, so TRAMP sends the login + name and a newline. + + * The remote host may prompt for a password or pass phrase (for + `rsh' or for `telnet' after sending the login name). TRAMP + displays the prompt in the minibuffer, asking you for the password + or pass phrase. + + You enter the password or pass phrase. TRAMP sends it to the + remote host, followed by a newline. + + * TRAMP now waits for the shell prompt or for a message that the + login failed. + + If TRAMP sees neither of them after a certain period of time (a + minute, say), then it issues an error message saying that it + couldn't find the remote shell prompt and shows you what the + remote host has sent. + + If TRAMP sees a `login failed' message, it tells you so, aborts + the login attempt and allows you to try again. + + * Suppose that the login was successful and TRAMP sees the shell + prompt from the remote host. Now TRAMP invokes `/bin/sh' because + Bourne shells and C shells have different command syntaxes.(1) + + After the Bourne shell has come up, TRAMP sends a few commands to + ensure a good working environment. It turns off echoing, it sets + the shell prompt, and a few other things. + + * Now the remote shell is up and it good working order. Remember, + what was supposed to happen is that TRAMP tries to find out what + files exist on the remote host so that it can do filename + completion. + + So, TRAMP basically issues `cd' and `ls' commands and also + sometimes `echo' with globbing. Another command that is often + used is `test' to find out whether a file is writable or a + directory or the like. The output of each command is parsed for + the necessary operation. + + * Suppose you are finished with filename completion, have entered + `C-x C-f', a full file name and hit `'. Now comes the time to + transfer the file contents from the remote host to the local host + so that you can edit them. + + See above for an explanation of how TRAMP transfers the file + contents. + + For inline transfers, TRAMP issues a command like `mimencode -b + /path/to/remote/file', waits until the output has accumulated in + the buffer that's used for communication, then decodes that output + to produce the file contents. + + For out-of-band transfers, TRAMP issues a command like the + following: + rcp user@host:/path/to/remote/file /tmp/tramp.4711 + It then reads the local temporary file `/tmp/tramp.4711' into a + buffer and deletes the temporary file. + + * You now edit the buffer contents, blithely unaware of what has + happened behind the scenes. (Unless you have read this section, + that is.) When you are finished, you type `C-x C-s' to save the + buffer. + + * Again, TRAMP transfers the file contents to the remote host either + inline or out-of-band. This is the reverse of what happens when + reading the file. + + I hope this has provided you with a basic overview of what happens +behind the scenes when you open a file with TRAMP. + + ---------- Footnotes ---------- + + (1) Invoking `/bin/sh' will fail if your login shell doesn't +recognize `exec /bin/sh' as a valid command. Maybe you use the Scheme +shell `scsh'... + + +File: tramp.info, Node: Obtaining Tramp, Next: History, Prev: Overview, Up: Top + +2 Obtaining Tramp. +****************** + +TRAMP is freely available on the Internet and the latest release may be +downloaded from `ftp://ftp.gnu.org/gnu/tramp/'. This release includes +the full documentation and code for TRAMP, suitable for installation. +But GNU Emacs (22 or later) includes TRAMP already, and there is a +TRAMP package for XEmacs, as well. So maybe it is easier to just use +those. But if you want the bleeding edge, read on...... + + For the especially brave, TRAMP is available from CVS. The CVS +version is the latest version of the code and may contain incomplete +features or new issues. Use these versions at your own risk. + + Instructions for obtaining the latest development version of TRAMP +from CVS can be found by going to the Savannah project page at the +following URL and then clicking on the CVS link in the navigation bar +at the top. + +`http://savannah.gnu.org/projects/tramp/' + +Or follow the example session below: + + ] *cd ~/xemacs* + ] *export CVS_RSH="ssh"* + ] *cvs -z3 -d:ext:anoncvs@savannah.gnu.org:/cvsroot/tramp co tramp* + +You should now have a directory `~/xemacs/tramp' containing the latest +version of TRAMP. You can fetch the latest updates from the repository +by issuing the command: + + ] *cd ~/xemacs/tramp* + ] *export CVS_RSH="ssh"* + ] *cvs update -d* + +Once you've got updated files from the CVS repository, you need to run +`autoconf' in order to get an up-to-date `configure' script: + + ] *cd ~/xemacs/tramp* + ] *autoconf* + + +File: tramp.info, Node: History, Next: Configuration, Prev: Obtaining Tramp, Up: Top + +3 History of TRAMP +****************** + +Development was started end of November 1998. The package was called +`rssh.el', back then. It only provided one method to access a file, +using `ssh' to log in to a remote host and using `scp' to transfer the +file contents. After a while, the name was changed to `rcp.el', and +now it's TRAMP. Along the way, many more methods for getting a remote +shell and for transferring the file contents were added. Support for +VC was added. + + The most recent addition of major features were the multi-hop methods +added in April 2000 and the unification of TRAMP and Ange-FTP filenames +in July 2002. + + +File: tramp.info, Node: Configuration, Next: Usage, Prev: History, Up: Top + +4 Configuring TRAMP for use +*************************** + +TRAMP is (normally) fully functional when it is initially installed. +It is initially configured to use the `ssh' program to connect to the +remote host and to use base64 or uu encoding to transfer the files +through that shell connection. So in the easiest case, you just type +`C-x C-f' and then enter the filename `/[USER@MACHINE]/PATH/TO.FILE'. + + On some hosts, there are problems with opening a connection. These +are related to the behavior of the remote shell. See *Note Remote +shell setup::, for details on this. + + If you do not wish to use these commands to connect to the remote +host, you should change the default connection and transfer method that +TRAMP uses. There are several different methods that TRAMP can use to +connect to remote machines and transfer files (*note Connection +types::). + + If you don't know which method is right for you, see *Note Default +Method::. + +* Menu: + +* Connection types:: Types of connections made to remote machines. +* Inline methods:: Inline methods. +* External transfer methods:: External transfer methods. +* Multi-hop Methods:: Connecting to a remote host using multiple hops. +* Default Method:: Selecting a default method. + Here we also try to help those who + don't have the foggiest which method + is right for them. +* Customizing Methods:: Using Non-Standard Methods. +* Customizing Completion:: Selecting config files for user/host name completion. +* Password caching:: Reusing passwords for several connections. +* Remote Programs:: How TRAMP finds and uses programs on the remote machine. +* Remote shell setup:: Remote shell setup hints. +* Windows setup hints:: Issues with Cygwin ssh. +* Auto-save and Backup:: Auto-save and Backup. + + +File: tramp.info, Node: Connection types, Next: Inline methods, Up: Configuration + +4.1 Types of connections made to remote machines. +================================================= + +There are two basic types of transfer methods, each with its own +advantages and limitations. Both types of connection make use of a +remote shell access program such as `rsh', `ssh' or `telnet' to connect +to the remote machine. + + This connection is used to perform many of the operations that TRAMP +requires to make the remote file system transparently accessible from +the local machine. It is only when visiting files that the methods +differ. + + Loading or saving a remote file requires that the content of the file +be transfered between the two machines. The content of the file can be +transfered over the same connection used to log in to the remote +machine or the file can be transfered through another connection using +a remote copy program such as `rcp', `scp' or `rsync'. The former are +called "inline methods", the latter are called "out-of-band methods" or +"external transfer methods" ("external methods" for short). + + The performance of the external transfer methods is generally better +than that of the inline methods, at least for large files. This is +caused by the need to encode and decode the data when transferring +inline. + + The one exception to this rule are the `scp' based transfer methods. +While these methods do see better performance when actually +transferring files, the overhead of the cryptographic negotiation at +startup may drown out the improvement in file transfer times. + + External transfer methods should be configured such a way that they +don't require a password (with `ssh-agent', or such alike). If it +isn't possible, you should consider *Note Password caching::, otherwise +you will be prompted for a password every copy action. + + A variant of the inline methods are the "multi-hop methods". These +methods allow you to connect a remote host using a number `hops', each +of which connects to a different host. This is useful if you are in a +secured network where you need to go through a bastion host to connect +to the outside world. + + +File: tramp.info, Node: Inline methods, Next: External transfer methods, Prev: Connection types, Up: Configuration + +4.2 Inline methods +================== + +The inline methods in TRAMP are quite powerful and can work in +situations where you cannot use an external transfer program to connect. +Inline methods are the only methods that work when connecting to the +remote machine via telnet. (There are also strange inline methods which +allow you to transfer files between _user identities_ rather than +hosts, see below.) + + These methods depend on the existence of a suitable encoding and +decoding command on remote machine. Locally, TRAMP may be able to use +features of XEmacs to decode and encode the files or it may require +access to external commands to perform that task. + + TRAMP checks the availability and usability of commands like +`mimencode' (part of the `metamail' package) or `uuencode' on the +remote host. The first reliable command will be used. The search path +can be customized, see *Note Remote Programs::. + + If both commands aren't available on the remote host, TRAMP +transfers a small piece of Perl code to the remote host, and tries to +apply it for encoding and decoding. + +`rsh' + Connect to the remote host with `rsh'. Due to the unsecure + connection it is recommended for very local host topology only. + + On operating systems which provide the command `remsh' instead of + `rsh', you can use the method `remsh'. This is true for HP-UX or + Cray UNICOS, for example. + +`ssh' + Connect to the remote host with `ssh'. This is identical to the + previous option except that the `ssh' package is used, making the + connection more secure. + + There are also two variants, `ssh1' and `ssh2', that call `ssh -1' + and `ssh -2', respectively. This way, you can explicitly select + whether you want to use the SSH protocol version 1 or 2 to connect + to the remote host. (You can also specify in `~/.ssh/config', the + SSH configuration file, which protocol should be used, and use the + regular `ssh' method.) + + Two other variants, `ssh1_old' and `ssh2_old', use the `ssh1' and + `ssh2' commands explicitly. If you don't know what these are, you + do not need these options. + + All the methods based on `ssh' have an additional kludgy feature: + you can specify a host name which looks like `host#42' (the real + host name, then a hash sign, then a port number). This means to + connect to the given host but to also pass `-p 42' as arguments to + the `ssh' command. + +`telnet' + Connect to the remote host with `telnet'. This is as unsecure as + the `rsh' method. + +`su' + This method does not connect to a remote host at all, rather it + uses the `su' program to allow you to edit files as another user. + +`sudo' + This is similar to the `su' method, but it uses `sudo' rather than + `su' to become a different user. + + Note that `sudo' must be configured to allow you to start a shell + as the user. It would be nice if it was sufficient if `ls' and + `mimencode' were allowed, but that is not easy to implement, so I + haven't got around to it, yet. + +`sshx' + As you would expect, this is similar to `ssh', only a little + different. Whereas `ssh' opens a normal interactive shell on the + remote host, this option uses `ssh -t -t HOST -l USER /bin/sh' to + open a connection. This is useful for users where the normal + login shell is set up to ask them a number of questions when + logging in. This procedure avoids these questions, and just gives + TRAMP a more-or-less `standard' login shell to work with. + + Note that this procedure does not eliminate questions asked by + `ssh' itself. For example, `ssh' might ask "Are you sure you want + to continue connecting?" if the host key of the remote host is not + known. TRAMP does not know how to deal with such a question + (yet), therefore you will need to make sure that you can log in + without such questions. + + This is also useful for Windows users where `ssh', when invoked + from an XEmacs buffer, tells them that it is not allocating a + pseudo tty. When this happens, the login shell is wont to not + print any shell prompt, which confuses TRAMP mightily. For + reasons unknown, some Windows ports for `ssh' require the doubled + `-t' option. + + This supports the `-p' kludge. + +`krlogin' + This method is also similar to `ssh'. It only uses the `krlogin + -x' command to log in to the remote host. + +`plink' + This method is mostly interesting for Windows users using the PuTTY + implementation of SSH. It uses `plink -ssh' to log in to the + remote host. + + Additionally, the method `plink1' is provided, which calls `plink + -1 -ssh' in order to use SSH protocol version 1 explicitely. + + CCC: Do we have to connect to the remote host once from the command + line to accept the SSH key? Maybe this can be made automatic? + + CCC: Does `plink' support the `-p' option? TRAMP will support + that, anyway. + + + +File: tramp.info, Node: External transfer methods, Next: Multi-hop Methods, Prev: Inline methods, Up: Configuration + +4.3 External transfer methods +============================= + +The external transfer methods operate through multiple channels, using +the remote shell connection for many actions while delegating file +transfers to an external transfer utility. + + This saves the overhead of encoding and decoding that multiplexing +the transfer through the one connection has with the inline methods. + + If you want to use an external transfer method you should be able to +execute the transfer utility to copy files to and from the remote +machine without any interaction. + + This means that you will need to use `ssh-agent' if you use the +`scp' program for transfers, or maybe your version of `scp' accepts a +password on the command line.(1) If you use `rsync' via `ssh' then the +same rule must apply to that connection. + + If you cannot get an external method to run without asking for a +password you should consider *Note Password caching::. + +`rcp' -- `rsh' and `rcp' + This method uses the `rsh' and `rcp' commands to connect to the + remote machine and transfer files. This is probably the fastest + connection method available. + + The alternative method `remcp' uses the `remsh' and `rcp' + commands. It should be applied on machines where `remsh' is used + instead of `rsh'. + +`scp' -- `ssh' and `scp' + Using `ssh' to connect to the remote host and `scp' to transfer + files between the machines is the best method for securely + connecting to a remote machine and accessing files. + + The performance of this option is also quite good. It may be + slower than the inline methods when you often open and close small + files however. The cost of the cryptographic handshake at the + start of an `scp' session can begin to absorb the advantage that + the lack of encoding and decoding presents. + + There are also two variants, `scp1' and `scp2', that call `ssh -1' + and `ssh -2', respectively. This way, you can explicitly select + whether you want to use the SSH protocol version 1 or 2 to connect + to the remote host. (You can also specify in `~/.ssh/config', the + SSH configuration file, which protocol should be used, and use the + regular `scp' method.) + + Two other variants, `scp1_old' and `scp2_old', use the `ssh1' and + `ssh2' commands explicitly. If you don't know what these are, you + do not need these options. + + All the `ssh' based methods support the kludgy `-p' feature where + you can specify a port number to connect to in the host name. For + example, the host name `host#42' tells TRAMP to specify `-p 42' in + the argument list for `ssh'. + +`rsync' -- `ssh' and `rsync' + Using the `ssh' command to connect securely to the remote machine + and the `rsync' command to transfer files is almost identical to + the `scp' method. + + While `rsync' performs much better than `scp' when transferring + files that exist on both hosts, this advantage is lost if the file + exists only on one side of the connection. + + The `rsync' based method may be considerably faster than the `rcp' + based methods when writing to the remote system. Reading files to + the local machine is no faster than with a direct copy. + + This method supports the `-p' hack. + +`scpx' -- `ssh' and `scp' + As you would expect, this is similar to `scp', only a little + different. Whereas `scp' opens a normal interactive shell on the + remote host, this option uses `ssh -t -t HOST -l USER /bin/sh' to + open a connection. This is useful for users where the normal + login shell is set up to ask them a number of questions when + logging in. This procedure avoids these questions, and just gives + TRAMP a more-or-less `standard' login shell to work with. + + This is also useful for Windows users where `ssh', when invoked + from an XEmacs buffer, tells them that it is not allocating a + pseudo tty. When this happens, the login shell is wont to not + print any shell prompt, which confuses TRAMP mightily. + + This method supports the `-p' hack. + +`pscp' -- `plink' and `pscp' + This method is similar to `scp', but it uses the `plink' command + to connect to the remote host, and it uses `pscp' for transferring + the files. These programs are part of PuTTY, an SSH + implementation for Windows. + + CCC: Does `plink' support the `-p' hack? + +`fcp' -- `fsh' and `fcp' + This method is similar to `scp', but it uses the `fsh' command to + connect to the remote host, and it uses `fcp' for transferring the + files. `fsh/fcp' are a front-end for `ssh' which allow for + reusing the same `ssh' session for submitting several commands. + This avoids the startup overhead of `scp' (which has to establish + a secure connection whenever it is called). Note, however, that + you can also use one of the inline methods to achieve a similar + effect. + + This method uses the command `fsh HOST -l USER /bin/sh -i' to + establish the connection, it does not work to just say `fsh HOST + -l USER'. + + There is no inline method using `fsh' as the multiplexing provided + by the program is not very useful in our context. TRAMP opens + just one connection to the remote host and then keeps it open, + anyway. + +`ftp' + This is not a native TRAMP method. Instead of, it forwards all + requests to EFS. This works only for unified filenames, see *Note + Issues::. + +`smb' -- `smbclient' + This is another not natural TRAMP method. It uses the `smbclient' + command on different Unices in order to connect to an SMB server. + An SMB server might be a Samba (or CIFS) server on another UNIX + host or, more interesting, a host running MS Windows. So far, it + is tested towards MS Windows NT, MS Windows 2000, and MS Windows + XP. + + The first directory in the localname must be a share name on the + remote host. Remember, that the `$' character in which default + shares usually end, must be written `$$' due to environment + variable substitution in file names. If no share name is given + (i.e. remote directory `/'), all available shares are listed. + + Since authorization is done on share level, you will be prompted + always for a password if you access another share on the same host. + This can be suppressed by *Note Password caching::. + + MS Windows uses for authorization both a user name and a domain + name. Because of this, the TRAMP syntax has been extended: you can + specify a user name which looks like `user%domain' (the real user + name, then a percent sign, then the domain name). So, to connect + to the machine `melancholia' as user `daniel' of the domain + `BIZARRE', and edit `.emacs' in the home directory (share + `daniel$') I would specify the filename + `/[smb/daniel%BIZARRE@melancholia]/daniel$$/.emacs'. + + The domain name as well as the user name are optional. If no user + name is specified at all, the anonymous user (without password + prompting) is assumed. This is different from all other TRAMP + methods, where in such a case the local user name is taken. + + The `smb' method supports the `-p' hack. + + *Please note:* If XEmacs runs locally under MS Windows, this + method isn't available. Instead of, you can use UNC file names + like `//melancholia/daniel$$/.emacs'. The only disadvantage is + that there's no possibility to specify another user name. + + + ---------- Footnotes ---------- + + (1) PuTTY's `pscp' allows you to specify the password on the command +line. + + +File: tramp.info, Node: Multi-hop Methods, Next: Default Method, Prev: External transfer methods, Up: Configuration + +4.4 Connecting to a remote host using multiple hops +=================================================== + +Sometimes, the methods described before are not sufficient. Sometimes, +it is not possible to connect to a remote host using a simple command. +For example, if you are in a secured network, you might have to log in +to a `bastion host' first before you can connect to the outside world. +Of course, the target host may also require a bastion host. The format +of multi-hop filenames is slightly different than the format of normal +TRAMP methods. + + A multi-hop file name specifies a method, a number of hops, and a +localname (path name on the remote system). The method name is always +`multi'. + + Each hop consists of a "hop method" specification, a user name and a +host name. The hop method can be an inline method only. The following +hop methods are (currently) available: + +`telnet' + Uses the well-known `telnet' program to connect to the host. + Whereas user name and host name are supplied in the file name, the + user is queried for the password. + +`rsh' + This uses `rsh' to connect to the host. You do not need to enter + a password unless `rsh' explicitly asks for it. + + The variant `remsh' uses the `remsh' command. It should be + applied on machines where `remsh' is used instead of `rsh'. + +`ssh' + This uses `ssh' to connect to the host. You might have to enter a + password or a pass phrase. + +`su' + This method does not actually contact a different host, but it + allows you to become a different user on the host you're currently + on. This might be useful if you want to edit files as root, but + the remote host does not allow remote root logins. In this case + you can use `telnet', `rsh' or `ssh' to connect to the remote host + as a non-root user, then use an `su' hop to become root. But `su' + need not be the last hop in a sequence, you could also use it + somewhere in the middle, if the need arises. + + Even though you _must_ specify both user and host with an `su' + hop, the host name is ignored and only the user name is used. + +`sudo' + This is similar to the `su' hop, except that it uses `sudo' rather + than `su' to become a different user. + + + Some people might wish to use port forwarding with `ssh' or maybe +they have to use a nonstandard port. This can be accomplished by +putting a stanza in `~/.ssh/config' for the account which specifies a +different port number for a certain host name. But it can also be +accomplished within TRAMP, by adding a multi-hop method. For example: + + (add-to-list + 'tramp-multi-connection-function-alist + '("sshf" tramp-multi-connect-rlogin "ssh %h -l %u -p 4400%n")) + + Now you can use an `sshf' hop which connects to port 4400 instead of +the standard port. + + +File: tramp.info, Node: Default Method, Next: Customizing Methods, Prev: Multi-hop Methods, Up: Configuration + +4.5 Selecting a default method +============================== + +When you select an appropriate transfer method for your typical usage +you should set the variable `tramp-default-method' to reflect that +choice. This variable controls which method will be used when a method +is not specified in the TRAMP file name. For example: + + (setq tramp-default-method "scp") + + You can also specify different methods for certain user/host +combinations, via the variable `tramp-default-method-alist'. For +example, the following two lines specify to use the `ssh' method for +all user names matching `john' and the `rsync' method for all host +names matching `lily'. The third line specifies to use the `su' method +for the user `root' on the machine `localhost'. + + (add-to-list 'tramp-default-method-alist '("" "john" "ssh")) + (add-to-list 'tramp-default-method-alist '("lily" "" "rsync")) + (add-to-list 'tramp-default-method-alist + '("\\`localhost\\'" "\\`root\\'" "su")) + +See the documentation for the variable `tramp-default-method-alist' for +more details. + + External transfer methods are normally preferable to inline transfer +methods, giving better performance. + + *Note Inline methods::. *Note External transfer methods::. *Note +Multi-hop Methods::. + + Another consideration with the selection of transfer methods is the +environment you will use them in and, especially when used over the +Internet, the security implications of your preferred method. + + The `rsh' and `telnet' methods send your password as plain text as +you log in to the remote machine, as well as transferring the files in +such a way that the content can easily be read from other machines. + + If you need to connect to remote systems that are accessible from the +Internet, you should give serious thought to using `ssh' based methods +to connect. These provide a much higher level of security, making it a +non-trivial exercise for someone to obtain your password or read the +content of the files you are editing. + +4.5.1 Which method is the right one for me? +------------------------------------------- + +Given all of the above, you are probably thinking that this is all fine +and good, but it's not helping you to choose a method! Right you are. +As a developer, we don't want to boss our users around but give them +maximum freedom instead. However, the reality is that some users would +like to have some guidance, so here I'll try to give you this guidance +without bossing you around. You tell me whether it works ... + + My suggestion is to use an inline method. For large files, +out-of-band methods might be more efficient, but I guess that most +people will want to edit mostly small files. + + I guess that these days, most people can access a remote machine by +using `ssh'. So I suggest that you use the `ssh' method. So, type +`C-x C-f /[ssh/root@otherhost]/etc/motd ' to edit the `/etc/motd' +file on the other host. + + If you can't use `ssh' to log in to the remote host, then select a +method that uses a program that works. For instance, Windows users +might like the `plink' method which uses the PuTTY implementation of +`ssh'. Or you use Kerberos and thus like `krlogin'. + + For the special case of editing files on the local host as another +user, see the `su' or `sudo' methods. They offer shortened syntax for +the `root' account, like `/[su/]/etc/motd'. + + People who edit large files may want to consider `scp' instead of +`ssh', or `pscp' instead of `plink'. These out-of-band methods are +faster than inline methods for large files. Note, however, that +out-of-band methods suffer from some limitations. Please try first +whether you really get a noticeable speed advantage from using an +out-of-band method! Maybe even for large files, inline methods are +fast enough. + + +File: tramp.info, Node: Customizing Methods, Next: Customizing Completion, Prev: Default Method, Up: Configuration + +4.6 Using Non-Standard Methods +============================== + +There is a variable `tramp-methods' which you can change if the +predefined methods don't seem right. + + For the time being, I'll refer you to the Lisp documentation of that +variable, accessible with `C-h v tramp-methods '. + + +File: tramp.info, Node: Customizing Completion, Next: Password caching, Prev: Customizing Methods, Up: Configuration + +4.7 Selecting config files for user/host name completion +======================================================== + +The variable `tramp-completion-function-alist' is intended to customize +which files are taken into account for user and host name completion +(*note Filename completion::). For every method, it keeps a set of +configuration files, accompanied by a Lisp function able to parse that +file. Entries in `tramp-completion-function-alist' have the form +(METHOD PAIR1 PAIR2 ...). + + Each PAIR is composed of (FUNCTION FILE). FUNCTION is responsible +to extract user names and host names from FILE for completion. There +are two functions which access this variable: + + -- Function: tramp-get-completion-function method + This function returns the list of completion functions for METHOD. + + Example: + (tramp-get-completion-function "rsh") + + => ((tramp-parse-rhosts "/etc/hosts.equiv") + (tramp-parse-rhosts "~/.rhosts")) + + -- Function: tramp-set-completion-function method function-list + This function sets FUNCTION-LIST as list of completion functions + for METHOD. + + Example: + (tramp-set-completion-function "ssh" + '((tramp-parse-sconfig "/etc/ssh_config") + (tramp-parse-sconfig "~/.ssh/config"))) + + => ((tramp-parse-sconfig "/etc/ssh_config") + (tramp-parse-sconfig "~/.ssh/config")) + + The following predefined functions parsing configuration files exist: + +`tramp-parse-rhosts' + This function parses files which are syntactical equivalent to + `~/.rhosts'. It returns both host names and user names, if + specified. + +`tramp-parse-shosts' + This function parses files which are syntactical equivalent to + `~/.ssh/known_hosts'. Since there are no user names specified in + such files, it can return host names only. + +`tramp-parse-sconfig' + This function returns the host nicknames defined by `Host' entries + in `~/.ssh/config' style files. + +`tramp-parse-shostkeys' + SSH2 parsing of directories `/etc/ssh2/hostkeys/*' and + `~/ssh2/hostkeys/*'. Hosts are coded in file names + `hostkey_PORTNUMBER_HOST-NAME.pub'. User names are always `nil'. + +`tramp-parse-sknownhosts' + Another SSH2 style parsing of directories like + `/etc/ssh2/knownhosts/*' and `~/ssh2/knownhosts/*'. This case, + hosts names are coded in file names `HOST-NAME.ALGORITHM.pub'. + User names are always `nil'. + +`tramp-parse-hosts' + A function dedicated to `/etc/hosts' style files. It returns host + names only. + +`tramp-parse-passwd' + A function which parses `/etc/passwd' like files. Obviously, it + can return user names only. + +`tramp-parse-netrc' + Finally, a function which parses `~/.netrc' like files. + + If you want to keep your own data in a file, with your own structure, +you might provide such a function as well. This function must meet the +following conventions: + + -- Function: my-tramp-parse file + FILE must be either a file name on your host, or `nil'. The + function must return a list of (USER HOST), which are taken as + candidates for user and host name completion. + + Example: + (my-tramp-parse "~/.my-tramp-hosts") + + => ((nil "toto") ("daniel" "melancholia")) + + +File: tramp.info, Node: Password caching, Next: Remote Programs, Prev: Customizing Completion, Up: Configuration + +4.8 Reusing passwords for several connections. +============================================== + +Sometimes it is necessary to connect to the same remote host several +times. Reentering passwords again and again would be annoying, when +the choosen method does not support access without password prompt +throught own configuration. + + By default, TRAMP caches the passwords entered by you. They will be +reused next time if a connection needs them for the same user name and +host name, independant of the connection method. + + Passwords are not saved permanently, that means the password caching +is limited to the lifetime of your XEmacs session. You can influence +the lifetime of password caching by customizing the variable +`password-cache-expiry'. The value is the number of seconds how long +passwords are cached. Setting it to `nil' disables the expiration. + + A password is removed from the cache if a connection isn't +established successfully. You can remove a password from the cache +also by executing `M-x tramp-clear-passwd' in a buffer containing a +related remote file or directory. + + If you don't like this feature for security reasons, password caching +can be disabled totally by customizing the variable `password-cache' +(setting it to `nil'). + + Implementation Note: password caching is based on the package +password.el in No Gnus. For the time being, it is activated only when +this package is seen in the `load-path' while loading TRAMP. It will +be activated mandatory once No Gnus has found its way into XEmacs. + + +File: tramp.info, Node: Remote Programs, Next: Remote shell setup, Prev: Password caching, Up: Configuration + +4.9 How TRAMP finds and uses programs on the remote machine. +============================================================ + +TRAMP depends on a number of programs on the remote host in order to +function, including `ls', `test', `find' and `cat'. + + In addition to these required tools, there are various tools that +may be required based on the connection method. See *Note Inline +methods:: and *Note External transfer methods:: for details on these. + + Certain other tools, such as `perl' (or `perl5') and `grep' will be +used if they can be found. When they are available, they are used to +improve the performance and accuracy of remote file access. + + When TRAMP connects to the remote machine, it searches for the +programs that it can use. The variable TRAMP-REMOTE-PATH controls the +directories searched on the remote machine. + + By default, this is set to a reasonable set of defaults for most +machines. It is possible, however, that your local (or remote ;) system +administrator has put the tools you want in some obscure local +directory. + + In this case, you can still use them with TRAMP. You simply need to +add code to your `.emacs' to add the directory to the remote path. +This will then be searched by TRAMP when you connect and the software +found. + + To add a directory to the remote search path, you could use code such +as: + + ;; We load TRAMP to define the variable. + (require 'tramp) + ;; We have `perl' in "/usr/local/perl/bin" + (add-to-list 'tramp-remote-path "/usr/local/perl/bin") + + +File: tramp.info, Node: Remote shell setup, Next: Windows setup hints, Prev: Remote Programs, Up: Configuration + +4.10 Remote shell setup hints +============================= + +As explained in the *Note Overview:: section, TRAMP connects to the +remote host and talks to the shell it finds there. Of course, when you +log in, the shell executes its init files. Suppose your init file +requires you to enter the birth date of your mother; clearly TRAMP does +not know this and hence fails to log you in to that host. + + There are different possible strategies for pursuing this problem. +One strategy is to enable TRAMP to deal with all possible situations. +This is a losing battle, since it is not possible to deal with _all_ +situations. The other strategy is to require you to set up the remote +host such that it behaves like TRAMP expects. This might be +inconvenient because you have to invest a lot of effort into shell +setup before you can begin to use TRAMP. + + The package, therefore, pursues a combined approach. It tries to +figure out some of the more common setups, and only requires you to +avoid really exotic stuff. For example, it looks through a list of +directories to find some programs on the remote host. And also, it +knows that it is not obvious how to check whether a file exists, and +therefore it tries different possibilities. (On some hosts and shells, +the command `test -e' does the trick, on some hosts the shell builtin +doesn't work but the program `/usr/bin/test -e' or `/bin/test -e' +works. And on still other hosts, `ls -d' is the right way to do this.) + + Below you find a discussion of a few things that TRAMP does not deal +with, and that you therefore have to set up correctly. + +SHELL-PROMPT-PATTERN + After logging in to the remote host, TRAMP has to wait for the + remote shell startup to finish before it can send commands to the + remote shell. The strategy here is to wait for the shell prompt. + In order to recognize the shell prompt, the variable + `shell-prompt-pattern' has to be set correctly to recognize the + shell prompt on the remote host. + + Note that TRAMP requires the match for `shell-prompt-pattern' to + be at the end of the buffer. Many people have something like the + following as the value for the variable: `"^[^>$][>$] *"'. Now + suppose your shell prompt is `a c $ '. In this case, TRAMP + recognizes the `>' character as the end of the prompt, but it is + not at the end of the buffer. + +TRAMP-SHELL-PROMPT-PATTERN + This regular expression is used by TRAMP in the same way as + `shell-prompt-pattern', to match prompts from the remote shell. + This second variable exists because the prompt from the remote + shell might be different from the prompt from a local shell -- + after all, the whole point of TRAMP is to log in to remote hosts + as a different user. The default value of + `tramp-shell-prompt-pattern' is the same as the default value of + `shell-prompt-pattern', which is reported to work well in many + circumstances. + +`tset' and other questions + Some people invoke the `tset' program from their shell startup + scripts which asks the user about the terminal type of the shell. + Maybe some shells ask other questions when they are started. TRAMP + does not know how to answer these questions. There are two + approaches for dealing with this problem. One approach is to take + care that the shell does not ask any questions when invoked from + TRAMP. You can do this by checking the `TERM' environment + variable, it will be set to `dumb' when connecting. + + The variable `tramp-terminal-type' can be used to change this value + to `dumb'. + + The other approach is to teach TRAMP about these questions. See + the variables `tramp-actions-before-shell' and + `tramp-multi-actions' (for multi-hop connections). + +Environment variables named like users in `.profile' + If you have a user named frumple and set the variable `FRUMPLE' in + your shell environment, then this might cause trouble. Maybe + rename the variable to `FRUMPLE_DIR' or the like. + + This weird effect was actually reported by a TRAMP user! + +Non-Bourne commands in `.profile' + After logging in to the remote host, TRAMP issues the command + `exec /bin/sh'. (Actually, the command is slightly different.) + When `/bin/sh' is executed, it reads some init files, such as + `~/.shrc' or `~/.profile'. + + Now, some people have a login shell which is not `/bin/sh' but a + Bourne-ish shell such as bash or ksh. Some of these people might + put their shell setup into the files `~/.shrc' or `~/.profile'. + This way, it is possible for non-Bourne constructs to end up in + those files. Then, `exec /bin/sh' might cause the Bourne shell to + barf on those constructs. + + As an example, imagine somebody putting `export FOO=bar' into the + file `~/.profile'. The standard Bourne shell does not understand + this syntax and will emit a syntax error when it reaches this line. + + Another example is the tilde (`~') character, say when adding + `~/bin' to `$PATH'. Many Bourne shells will not expand this + character, and since there is usually no directory whose name + consists of the single character tilde, strange things will happen. + + What can you do about this? + + Well, one possibility is to make sure that everything in `~/.shrc' + and `~/.profile' on all remote hosts is Bourne-compatible. In the + above example, instead of `export FOO=bar', you might use + `FOO=bar; export FOO' instead. + + The other possibility is to put your non-Bourne shell setup into + some other files. For example, bash reads the file + `~/.bash_profile' instead of `~/.profile', if the former exists. + So bash aficionados just rename their `~/.profile' to + `~/.bash_profile' on all remote hosts, and Bob's your uncle. + + The TRAMP developers would like to circumvent this problem, so if + you have an idea about it, please tell us. However, we are afraid + it is not that simple: before saying `exec /bin/sh', TRAMP does + not know which kind of shell it might be talking to. It could be + a Bourne-ish shell like ksh or bash, or it could be a csh + derivative like tcsh, or it could be zsh, or even rc. If the + shell is Bourne-ish already, then it might be prudent to omit the + `exec /bin/sh' step. But how to find out if the shell is + Bourne-ish? + + + +File: tramp.info, Node: Auto-save and Backup, Prev: Windows setup hints, Up: Configuration + +4.11 Auto-save and Backup configuration +======================================= + +Normally, XEmacs writes backup files to the same directory as the +original files, but this behavior can be changed via the variable +`bkup-backup-directory-info'. In connection with TRAMP, this can have +unexpected side effects. Suppose that you specify that all backups +should go to the directory `~/.emacs.d/backups/', and then you edit the +file `/[su/root@localhost]/etc/secretfile'. The effect is that the +backup file will be owned by you and not by root, thus possibly +enabling others to see it even if they were not intended to see it. + + When `bkup-backup-directory-info' is `nil' (the default), such +problems do not occur. + + Therefore, it is usefull to set special values for TRAMP files. For +example, the following statement effectively `turns off' the effect of +`bkup-backup-directory-info' for TRAMP files: + + (require 'backup-dir) + (add-to-list 'bkup-backup-directory-info + (list tramp-file-name-regexp "")) + + Another possibility is to use the TRAMP variable +`tramp-bkup-backup-directory-info'. This variable has the same meaning +like `bkup-backup-directory-info'. If a TRAMP file is backed up, and +DIRECTORY is an absolute local file name, DIRECTORY is prepended with +the TRAMP file name prefix of the file to be backed up. + +Example: + + (require 'backup-dir) + (add-to-list 'bkup-backup-directory-info + (list "." "~/.emacs.d/backups/" 'full-path)) + (setq tramp-bkup-backup-directory-info bkup-backup-directory-info) + +The backup file name of `/[su/root@localhost]/etc/secretfile' would be +`/[su/root@localhost]~/.emacs.d/backups/![su!root@localhost]!etc!secretfile~' + + The same problem can happen with auto-saving files. For this +purpose you can set the variable `auto-save-directory' to a proper +value. + + +File: tramp.info, Node: Windows setup hints, Next: Auto-save and Backup, Prev: Remote shell setup, Up: Configuration + +4.12 Issues with Cygwin ssh +=========================== + +This section needs a lot of work! Please help. + + The recent Cygwin installation of `ssh' works only with a Cygwinized +XEmacs. You can check it by typing `M-x eshell', and starting `ssh +test.machine'. The problem is evident if you see a message like this: + + Pseudo-terminal will not be allocated because stdin is not a terminal. + + Older `ssh' versions of Cygwin are told to cooperate with TRAMP +selecting `sshx' as the connection method. You can find information +about setting up Cygwin in their FAQ at `http://cygwin.com/faq/'. + + If you wish to use the `scpx' connection method, then you might have +the problem that XEmacs calls `scp' with a Windows filename such as +`c:/foo'. The Cygwin version of `scp' does not know about Windows +filenames and interprets this as a remote filename on the host `c'. + + One possible workaround is to write a wrapper script for `scp' which +converts the Windows filename to a Cygwinized filename. + + If you want to use either `ssh' based method on Windows, then you +might encounter problems with `ssh-agent'. Using this program, you can +avoid typing the pass-phrase every time you log in. However, if you +start XEmacs from a desktop shortcut, then the environment variable +`SSH_AUTH_SOCK' is not set and so XEmacs and thus TRAMP and thus `ssh' +and `scp' started from TRAMP cannot communicate with `ssh-agent'. It +works better to start XEmacs from the shell. + + If anyone knows how to start `ssh-agent' under Windows in such a way +that desktop shortcuts can profit, please holler. I don't really know +anything at all about Windows... + + +File: tramp.info, Node: Usage, Next: Bug Reports, Prev: Configuration, Up: Top + +5 Using TRAMP +************* + +Once you have installed TRAMP it will operate fairly transparently. You +will be able to access files on any remote machine that you can log in +to as though they were local. + + Files are specified to TRAMP using a formalized syntax specifying the +details of the system to connect to. This is similar to the syntax used +by the EFS package. + + Something that might happen which surprises you is that XEmacs +remembers all your keystrokes, so if you see a password prompt from +XEmacs, say, and hit `' twice instead of once, then the second +keystroke will be processed by XEmacs after TRAMP has done its thing. +Why, this type-ahead is normal behavior, you say. Right you are, but +be aware that opening a remote file might take quite a while, maybe +half a minute when a connection needs to be opened. Maybe after half a +minute you have already forgotten that you hit that key! + +* Menu: + +* Filename Syntax:: TRAMP filename conventions. +* Multi-hop filename syntax:: Multi-hop filename conventions. +* Filename completion:: Filename completion. +* Dired:: Dired. +* Compilation:: Compile remote files. + + +File: tramp.info, Node: Filename Syntax, Next: Multi-hop filename syntax, Up: Usage + +5.1 TRAMP filename conventions +============================== + +To access the file LOCALNAME on the remote machine MACHINE you would +specify the filename `/[MACHINE]LOCALNAME'. This will connect to +MACHINE and transfer the file using the default method. *Note Default +Method::. + + Some examples of TRAMP filenames are shown below. + +`/[melancholia].emacs' + Edit the file `.emacs' in your home directory on the machine + `melancholia'. + +`/[melancholia.danann.net].emacs' + This edits the same file, using the fully qualified domain name of + the machine. + +`/[melancholia]~/.emacs' + This also edits the same file -- the `~' is expanded to your home + directory on the remote machine, just like it is locally. + +`/[melancholia]~daniel/.emacs' + This edits the file `.emacs' in the home directory of the user + `daniel' on the machine `melancholia'. The `~' construct is + expanded to the home directory of that user on the remote machine. + +`/[melancholia]/etc/squid.conf' + This edits the file `/etc/squid.conf' on the machine `melancholia'. + + + Unless you specify a different name to use, TRAMP will use the +current local user name as the remote user name to log in with. If you +need to log in as a different user, you can specify the user name as +part of the filename. + + To log in to the remote machine as a specific user, you use the +syntax `/[USER@MACHINE]/PATH/TO.FILE'. That means that connecting to +`melancholia' as `daniel' and editing `.emacs' in your home directory +you would specify `/[daniel@melancholia].emacs'. + + It is also possible to specify other file transfer methods (*note +Default Method::) as part of the filename. This is done by replacing +the initial `/[' with `/[/'. (Note the trailing slash!). The +user, machine and file specification remain the same. + + So, to connect to the machine `melancholia' as `daniel', using the +`ssh' method to transfer files, and edit `.emacs' in my home directory +I would specify the filename `/[ssh/daniel@melancholia].emacs'. + + +File: tramp.info, Node: Multi-hop filename syntax, Next: Filename completion, Prev: Filename Syntax, Up: Usage + +5.2 Multi-hop filename conventions +================================== + +The syntax of multi-hop file names is necessarily slightly different +than the syntax of other TRAMP file names. Here's an example multi-hop +file name: + + /[multi/rsh:out@gate/telnet:kai@real.host]/path/to.file + + This is quite a mouthful. So let's go through it step by step. The +file name consists of three parts. The parts are separated by slashes +and square brackets. The first part is `/[multi', the method +specification. The second part is `rsh:out@gate/telnet:kai@real.host' +and specifies the hops. The final part is `/path/to.file' and +specifies the file name on the remote host. + + The first part and the final part should be clear. See *Note +Multi-hop Methods::, for a list of alternatives for the method +specification. + + The second part can be subdivided again into components, so-called +hops. In the above file name, there are two hops, `rsh:out@gate' and +`telnet:kai@real.host'. + + Each hop can _again_ be subdivided into (three) components, the "hop +method", the "user name" and the "host name". The meaning of the +second and third component should be clear, and the hop method says +what program to use to perform that hop. + + The first hop, `rsh:out@gate', says to use `rsh' to log in as user +`out' to the host `gate'. Starting at that host, the second hop, +`telnet:kai@real.host', says to use `telnet' to log in as user `kai' to +host `real.host'. + + *Note Multi-hop Methods::, for a list of possible hop method values. +The variable `tramp-multi-connection-function-alist' contains the list +of possible hop methods and information on how to execute them, should +you want to add your own. + + +File: tramp.info, Node: Filename completion, Next: Dired, Prev: Multi-hop filename syntax, Up: Usage + +5.3 Filename completion +======================= + +Filename completion works with TRAMP for both completing methods, user +names and machine names (except multi hop methods) as well as for files +on remote machines. + + If you, for example, type `C-x C-f /[t ', TRAMP might give you +as result the choice for + + [telnet/ [toto] + + `[telnet/' is a possible completion for the respective method, and +`[toto]' might be a host TRAMP has detected in your `~/.ssh/known_hosts' +file (given you're using default method `ssh'). + + If you go on to type `e ', the minibuffer is completed to +`/[telnet/'. Next `' brings you all machine names TRAMP detects in +your `/etc/hosts' file, let's say + + [telnet/127.0.0.1] [telnet/192.168.0.1] + [telnet/localhost] [telnet/melancholia.danann.net] + [telnet/melancholia] + + Now you can choose the desired machine, and you can continue to +complete file names on that machine. + + As filename completion needs to fetch the listing of files from the +remote machine, this feature is sometimes fairly slow. As TRAMP does +not yet cache the results of directory listing, there is no gain in +performance the second time you complete filenames. + + If the configuration files (*note Customizing Completion::), which +TRAMP uses for analysis of completion, offer user names, those user +names will be taken into account as well. + + +File: tramp.info, Node: Dired, Next: Compilation, Prev: Filename completion, Up: Usage + +5.4 Dired +========= + +TRAMP works transparently with dired, enabling you to use this powerful +file management tool to manage files on any machine you have access to +over the Internet. + + If you need to browse a directory tree, Dired is a better choice, at +present, than filename completion. Dired has its own cache mechanism +and will only fetch the directory listing once. + + +File: tramp.info, Node: Compilation, Prev: Dired, Up: Usage + +5.5 Compile remote files +======================== + +TRAMP provides commands for compilation of files on remote machines. +In order to get them loaded, you need to require `tramp-util.el': + + (require 'tramp-util) + + Afterwards, you can use the commands `tramp-compile' and +`tramp-recompile' instead of `compile' and `recompile', respectively; +*note (xemacs)Compilation::. This does not work for the `ftp' and +`smb' methods. + + The corresponding key bindings and menu entries calling these +commands are redefined automatically for buffers associated with remote +files. + + After finishing the compilation, you can use the usual commands like +`previous-error', `next-error' and `first-error' for navigation in the +`*Compilation*' buffer. + + +File: tramp.info, Node: Bug Reports, Next: Frequently Asked Questions, Prev: Usage, Up: Top + +6 Reporting Bugs and Problems +***************************** + +Bugs and problems with TRAMP are actively worked on by the development +team. Feature requests and suggestions are also more than welcome. + + The TRAMP mailing list is a great place to get information on working +with TRAMP, solving problems and general discussion and advice on topics +relating to the package. + + The mailing list is at . Messages sent to this +address go to all the subscribers. This is _not_ the address to send +subscription requests to. + + Subscribing to the list is performed via the TRAMP Mail Subscription +Page (http://lists.gnu.org/mailman/listinfo/tramp-devel/). + + To report a bug in TRAMP, you should execute `M-x tramp-bug'. This +will automatically generate a buffer with the details of your system and +TRAMP version. + + When submitting a bug report, please try to describe in excruciating +detail the steps required to reproduce the problem, the setup of the +remote machine and any special conditions that exist. You should also +check that your problem is not described already in *Note Frequently +Asked Questions::. + + If you can identify a minimal test case that reproduces the problem, +include that with your bug report. This will make it much easier for the +development team to analyze and correct the problem. + + +File: tramp.info, Node: Frequently Asked Questions, Next: Concept Index, Prev: Bug Reports, Up: Top + +7 Frequently Asked Questions +**************************** + + * Where can I get the latest TRAMP? + + TRAMP is available under the URL below. + + `ftp://ftp.gnu.org/gnu/tramp/' + + There is also a Savannah project page. + + `http://savannah.gnu.org/projects/tramp/' + + * Which systems does it work on? + + The package has been used successfully on GNU Emacs 20, GNU Emacs + 21 and GNU Emacs 22, as well as XEmacs 21. XEmacs 20 is more + problematic, see the notes in `tramp.el'. I don't think anybody + has really tried it on GNU Emacs 19. + + The package was intended to work on Unix, and it really expects a + Unix-like system on the remote end (except the `smb' method), but + some people seemed to have some success getting it to work on MS + Windows NT/2000/XP XEmacs. + + There is some informations on TRAMP on NT at the following URL; + many thanks to Joe Stoy for providing the information: + `ftp://ftp.comlab.ox.ac.uk/tmp/Joe.Stoy/' + + ??? Is the XEmacs info correct? + + ??? Can somebody provide some information for getting it to work + on NT Emacs? I think there was some issue with `ssh'? + + * TRAMP does not connect to the remote host + + When TRAMP does not connect to the remote host, there are two + reasons heading the bug mailing list: + + - Unknown characters in the prompt + + TRAMP needs to recognize the prompt on the remote machine + after execution any command. This is not possible, when the + prompt contains unknown characters like escape sequences for + coloring. This should be avoided on the remote side. *Note + Remote shell setup::. for setting the regular expression + detecting the prompt. + + - TRAMP doesn't transfer strings with more than 500 characters + correctly + + On some few systems, the implementation of + `process-send-string' seems to be broken for longer strings. + This case, you should customize the variable + `tramp-chunksize' to 500. For a description how to determine + whether this is necessary see the documentation of + `tramp-chunksize'. + + * File name completion does not work with TRAMP + + When you log in to the remote machine, do you see the output of + `ls' in color? If so, this may be the cause of your problems. + + `ls' outputs ANSI escape sequences that your terminal emulator + interprets to set the colors. These escape sequences will confuse + TRAMP however. + + In your `.bashrc', `.profile' or equivalent on the remote machine + you probably have an alias configured that adds the option + `--color=yes' or `--color=auto'. + + You should remove that alias and ensure that a new login _does not_ + display the output of `ls' in color. If you still cannot use + filename completion, report a bug to the TRAMP developers. + + * File name completion does not work in large directories + + TRAMP uses globbing for some operations. (Globbing means to use + the shell to expand wildcards such as `*.c'.) This might create + long command lines, especially in directories with many files. + Some shells choke on long command lines, or don't cope well with + the globbing itself. + + If you have a large directory on the remote end, you may wish to + execute a command like `ls -d * ..?* > /dev/null' and see if it + hangs. Note that you must first start the right shell, which + might be `/bin/sh', `ksh' or `bash', depending on which of those + supports tilde expansion. + + * How can I get notified when TRAMP file transfers are complete? + + The following snippet can be put in your `~/.emacs' file. It + makes XEmacs beep after reading from or writing to the remote host. + + (defadvice tramp-handle-write-region + (after tramp-write-beep-advice activate) + " make tramp beep after writing a file." + (interactive) + (beep)) + (defadvice tramp-handle-do-copy-or-rename-file + (after tramp-copy-beep-advice activate) + " make tramp beep after copying a file." + (interactive) + (beep)) + (defadvice tramp-handle-insert-file-contents + (after tramp-copy-beep-advice activate) + " make tramp beep after copying a file." + (interactive) + (beep)) + + * There's this `~/.sh_history' file on the remote host which keeps + growing and growing. What's that? + + Sometimes, TRAMP starts `ksh' on the remote host for tilde + expansion. Maybe `ksh' saves the history by default. TRAMP tries + to turn off saving the history, but maybe you have to help. For + example, you could put this in your `.kshrc': + + if [ -f $HOME/.sh_history ] ; then + /bin/rm $HOME/.sh_history + fi + if [ "${HISTFILE-unset}" != "unset" ] ; then + unset HISTFILE + fi + if [ "${HISTSIZE-unset}" != "unset" ] ; then + unset HISTSIZE + fi + + * How can I disable TRAMP? + + Shame on you, why did you read until now? + + Unloading TRAMP can be achieved by applying `M-x + tramp-unload-tramp'. + + +File: tramp.info, Node: Version Control, Next: Files directories and localnames, Prev: Concept Index, Up: Top + +8 The inner workings of remote version control +********************************************** + +Unlike EFS, TRAMP has full shell access to the remote machine. This +makes it possible to provide version control for files accessed under +TRAMP. + + The actual version control binaries must be installed on the remote +machine, accessible in the directories specified in TRAMP-REMOTE-PATH. + + This transparent integration with the version control systems is one +of the most valuable features provided by TRAMP, but it is far from +perfect. Work is ongoing to improve the transparency of the system. + +* Menu: + +* Version Controlled Files:: Determining if a file is under version control. +* Remote Commands:: Executing the version control commands on the remote machine. +* Changed workfiles:: Detecting if the working file has changed. +* Checking out files:: Bringing the workfile out of the repository. +* Miscellaneous Version Control:: Things related to Version Control that don't fit elsewhere. + + +File: tramp.info, Node: Version Controlled Files, Next: Remote Commands, Up: Version Control + +8.1 Determining if a file is under version control +================================================== + +The VC package uses the existence of on-disk revision control master +files to determine if a given file is under revision control. These file +tests happen on the remote machine through the standard TRAMP +mechanisms. + + +File: tramp.info, Node: Remote Commands, Next: Changed workfiles, Prev: Version Controlled Files, Up: Version Control + +8.2 Executing the version control commands on the remote machine +================================================================ + +There are no hooks provided by VC to allow intercepting of the version +control command execution. The calls occur through the `call-process' +mechanism, a function that is somewhat more efficient than the +`shell-command' function but that does not provide hooks for remote +execution of commands. + + To work around this, the functions `vc-do-command' and +`vc-simple-command' have been advised to intercept requests for +operations on files accessed via TRAMP. + + In the case of a remote file, the `shell-command' interface is used, +with some wrapper code, to provide the same functionality on the remote +machine as would be seen on the local machine. + + +File: tramp.info, Node: Changed workfiles, Next: Checking out files, Prev: Remote Commands, Up: Version Control + +8.3 Detecting if the working file has changed +============================================= + +As there is currently no way to get access to the mtime of a file on a +remote machine in a portable way, the `vc-workfile-unchanged-p' +function is advised to call an TRAMP specific function for remote files. + + The `tramp-vc-workfile-unchanged-p' function uses the functioning VC +diff functionality to determine if any changes have occurred between the +workfile and the version control master. + + This requires that a shell command be executed remotely, a process +that is notably heavier-weight than the mtime comparison used for local +files. Unfortunately, unless a portable solution to the issue is found, +this will remain the cost of remote version control. + + +File: tramp.info, Node: Checking out files, Next: Miscellaneous Version Control, Prev: Changed workfiles, Up: Version Control + +8.4 Bringing the workfile out of the repository +=============================================== + +VC will, by default, check for remote files and refuse to act on them +when checking out files from the repository. To work around this +problem, the function `vc-checkout' knows about TRAMP files and allows +version control to occur. + + +File: tramp.info, Node: Miscellaneous Version Control, Prev: Checking out files, Up: Version Control + +8.5 Things related to Version Control that don't fit elsewhere +============================================================== + +Minor implementation details, &c. + +* Menu: + +* Remote File Ownership:: How VC determines who owns a workfile. +* Back-end Versions:: How VC determines what release your RCS is. + + +File: tramp.info, Node: Remote File Ownership, Next: Back-end Versions, Up: Miscellaneous Version Control + +8.5.1 How VC determines who owns a workfile +------------------------------------------- + +XEmacs provides the `user-full-name' function to return the login name +of the current user as well as mapping from arbitrary user id values +back to login names. The VC code uses this functionality to map from +the uid of the owner of a workfile to the login name in some +circumstances. + + This will not, for obvious reasons, work if the remote system has a +different set of logins. As such, it is necessary to delegate to the +remote machine the job of determining the login name associated with a +uid. + + Unfortunately, with the profusion of distributed management systems +such as `NIS', `NIS+' and `NetInfo', there is no simple, reliable and +portable method for performing this mapping. + + Thankfully, the only place in the VC code that depends on the +mapping of a uid to a login name is the `vc-file-owner' function. This +returns the login of the owner of the file as a string. + + This function has been advised to use the output of `ls' on the +remote machine to determine the login name, delegating the problem of +mapping the uid to the login to the remote system which should know more +about it than I do. + + +File: tramp.info, Node: Back-end Versions, Prev: Remote File Ownership, Up: Miscellaneous Version Control + +8.5.2 How VC determines what release your RCS is +------------------------------------------------ + +VC needs to know what release your revision control binaries you are +running as not all features VC supports are available with older +versions of `rcs(1)', `cvs(1)' or `sccs(1)'. + + The default implementation of VC determines this value the first +time it is needed and then stores the value globally to avoid the +overhead of executing a process and parsing its output each time the +information is needed. + + Unfortunately, life is not quite so easy when remote version control +comes into the picture. Each remote machine may have a different version +of the version control tools and, while this is painful, we need to +ensure that unavailable features are not used remotely. + + To resolve this issue, TRAMP currently takes the sledgehammer +approach of making the release values of the revision control tools +local to each TRAMP buffer, forcing VC to determine these values again +each time a new file is visited. + + This has, quite obviously, some performance implications. Thankfully, +most of the common operations performed by VC do not actually require +that the remote version be known. This makes the problem far less +apparent. + + Eventually these values will be captured by TRAMP on a system by +system basis and the results cached to improve performance. + + +File: tramp.info, Node: Files directories and localnames, Next: Issues, Prev: Version Control, Up: Top + +9 How file names, directories and localnames are mangled and managed. +********************************************************************* + +* Menu: + +* Localname deconstruction:: Breaking a localname into its components. + + +File: tramp.info, Node: Localname deconstruction, Up: Files directories and localnames + +9.1 Breaking a localname into its components. +============================================= + +TRAMP file names are somewhat different, obviously, to ordinary file +names. As such, the lisp functions `file-name-directory' and +`file-name-nondirectory' are overridden within the TRAMP package. + + Their replacements are reasonably simplistic in their approach. They +dissect the filename, call the original handler on the localname and +then rebuild the TRAMP file name with the result. + + This allows the platform specific hacks in the original handlers to +take effect while preserving the TRAMP file name information. + + +File: tramp.info, Node: Issues, Prev: Files directories and localnames, Up: Top + +10 Debatable Issues and What Was Decided +**************************************** + + * The uuencode method does not always work. + + Due to the design of TRAMP, the encoding and decoding programs + need to read from stdin and write to stdout. On some systems, + `uudecode -o -' will read stdin and write the decoded file to + stdout, on other systems `uudecode -p' does the same thing. But + some systems have uudecode implementations which cannot do this at + all--it is not possible to call these uudecode implementations with + suitable parameters so that they write to stdout. + + Of course, this could be circumvented: the `begin foo 644' line + could be rewritten to put in some temporary file name, then + `uudecode' could be called, then the temp file could be printed + and deleted. + + But I have decided that this is too fragile to reliably work, so + on some systems you'll have to do without the uuencode methods. + + * TRAMP does not work on XEmacs 20. + + This is because it requires the macro `with-timeout' which does not + appear to exist in XEmacs 20. I'm somewhat reluctant to add an + emulation macro to TRAMP, but if somebody who uses XEmacs 20 steps + forward and wishes to implement and test it, please contact me or + the mailing list. + + * The TRAMP filename syntax differs between GNU Emacs and XEmacs. + + The GNU Emacs maintainers wish to use a unified filename syntax for + Ange-FTP and TRAMP so that users don't have to learn a new syntax. + It is sufficient to learn some extensions to the old syntax. + + For the XEmacs maintainers, the problems caused from using a + unified filename syntax are greater than the gains. The XEmacs + package system uses EFS for downloading new packages. So, + obviously, EFS has to be installed from the start. If the + filenames were unified, TRAMP would have to be installed from the + start, too. + + *Note:* If you'ld like to use a similar syntax like EFS, you need + the following settings in your init file: + + (setq tramp-unified-filenames t) + (require 'tramp) + + The autoload of the XEmacs TRAMP package must be disabled. This + can be achieved by setting file permissions `000' to the files + `.../xemacs-packages/lisp/tramp/auto-autoloads.el*'. + + In case of unified filenames, all XEmacs download sites are added + to `tramp-default-method-alist' with default method `ftp' *Note + Default Method::. These settings shouldn't be touched for proper + working of the XEmacs package system. + + The syntax for unified filenames is described in the TRAMP manual + for GNU Emacs. + + +File: tramp.info, Node: Concept Index, Next: Version Control, Prev: Frequently Asked Questions, Up: Top + +Concept Index +************* + +[index] +* Menu: + +* .login file: Remote shell setup. (line 6) +* .profile file: Remote shell setup. (line 6) +* auto-save: Auto-save and Backup. + (line 6) +* backup: Auto-save and Backup. + (line 6) +* base-64 encoding: Inline methods. (line 18) +* behind the scenes: Overview. (line 53) +* bug reports: Bug Reports. (line 6) +* choosing the right method: Default Method. (line 51) +* compile: Compilation. (line 6) +* configuration: Configuration. (line 6) +* connection types, overview: Connection types. (line 6) +* create your own methods: Customizing Methods. (line 6) +* customizing completion: Customizing Completion. + (line 6) +* customizing methods: Customizing Methods. (line 6) +* Cygwin and ssh-agent: Windows setup hints. (line 26) +* Cygwin, issues: Windows setup hints. (line 6) +* default configuration: Configuration. (line 6) +* default method: Default Method. (line 6) +* details of operation: Overview. (line 53) +* development history: History. (line 6) +* dired: Dired. (line 6) +* external methods: Connection types. (line 16) +* external transfer methods <1>: External transfer methods. + (line 6) +* external transfer methods: Connection types. (line 16) +* FAQ: Frequently Asked Questions. + (line 6) +* fcp (with fcp method): External transfer methods. + (line 101) +* fcp method: External transfer methods. + (line 101) +* filename completion: Filename completion. (line 6) +* filename examples: Filename Syntax. (line 6) +* filename syntax: Filename Syntax. (line 6) +* filename syntax for multi-hop files: Multi-hop filename syntax. + (line 6) +* frequently asked questions: Frequently Asked Questions. + (line 6) +* fsh (with fcp method): External transfer methods. + (line 101) +* fsh method: External transfer methods. + (line 114) +* ftp method: External transfer methods. + (line 120) +* history: History. (line 6) +* hop method rsh: Multi-hop Methods. (line 28) +* hop method ssh: Multi-hop Methods. (line 35) +* hop method su: Multi-hop Methods. (line 39) +* hop method sudo: Multi-hop Methods. (line 52) +* hop method telnet: Multi-hop Methods. (line 23) +* how it works: Overview. (line 53) +* inline methods <1>: Inline methods. (line 6) +* inline methods: Connection types. (line 16) +* Kerberos (with krlogin method): Inline methods. (line 100) +* km krlogin: Inline methods. (line 100) +* method fcp: External transfer methods. + (line 101) +* method fsh: External transfer methods. + (line 114) +* method ftp: External transfer methods. + (line 120) +* method krlogin: Inline methods. (line 100) +* method multi: Multi-hop Methods. (line 14) +* method plink: Inline methods. (line 104) +* method pscp: External transfer methods. + (line 93) +* method rcp: External transfer methods. + (line 26) +* method rsh: Inline methods. (line 28) +* method rsync: External transfer methods. + (line 62) +* method scp: External transfer methods. + (line 35) +* method scpx: External transfer methods. + (line 77) +* method scpx with Cygwin: Windows setup hints. (line 18) +* method smb: External transfer methods. + (line 125) +* method ssh: Inline methods. (line 36) +* method sshx: Inline methods. (line 75) +* method sshx with Cygwin: Windows setup hints. (line 8) +* method su: Inline methods. (line 62) +* method sudo: Inline methods. (line 66) +* method telnet: Inline methods. (line 58) +* methods, external transfer <1>: External transfer methods. + (line 6) +* methods, external transfer: Connection types. (line 16) +* methods, inline <1>: Inline methods. (line 6) +* methods, inline: Connection types. (line 16) +* methods, multi-hop <1>: Multi-hop Methods. (line 6) +* methods, multi-hop: Connection types. (line 39) +* methods, out-of-band <1>: External transfer methods. + (line 6) +* methods, out-of-band: Connection types. (line 16) +* mimencode: Inline methods. (line 18) +* multi method: Multi-hop Methods. (line 14) +* multi-hop filename syntax: Multi-hop filename syntax. + (line 6) +* multi-hop methods <1>: Multi-hop Methods. (line 6) +* multi-hop methods: Connection types. (line 39) +* obtaining Tramp: Obtaining Tramp. (line 6) +* out-of-band methods <1>: External transfer methods. + (line 6) +* out-of-band methods: Connection types. (line 16) +* overview: Overview. (line 6) +* passwords: Password caching. (line 6) +* plink (with pscp method): External transfer methods. + (line 93) +* plink method: Inline methods. (line 104) +* pscp (with pscp method): External transfer methods. + (line 93) +* pscp method: External transfer methods. + (line 93) +* PuTTY (with pscp method): External transfer methods. + (line 93) +* rcp (with rcp method): External transfer methods. + (line 26) +* rcp method: External transfer methods. + (line 26) +* recompile: Compilation. (line 6) +* remote shell setup: Remote shell setup. (line 6) +* rsh (with rcp method): External transfer methods. + (line 26) +* rsh hop method: Multi-hop Methods. (line 28) +* rsh method: Inline methods. (line 28) +* rsync (with rsync method): External transfer methods. + (line 62) +* rsync method: External transfer methods. + (line 62) +* scp (with scp method): External transfer methods. + (line 35) +* scp (with scpx method): External transfer methods. + (line 77) +* scp method: External transfer methods. + (line 35) +* scpx method: External transfer methods. + (line 77) +* scpx method with Cygwin: Windows setup hints. (line 18) +* selecting config files: Customizing Completion. + (line 6) +* shell init files: Remote shell setup. (line 6) +* smb method: External transfer methods. + (line 125) +* ssh (with rsync method): External transfer methods. + (line 62) +* ssh (with scp method): External transfer methods. + (line 35) +* ssh (with scpx method): External transfer methods. + (line 77) +* ssh hop method: Multi-hop Methods. (line 35) +* ssh method: Inline methods. (line 36) +* ssh-agent: External transfer methods. + (line 17) +* SSH_AUTH_SOCK and XEmacs on Windows: Windows setup hints. (line 26) +* sshx method: Inline methods. (line 75) +* sshx method with Cygwin: Windows setup hints. (line 8) +* su hop method: Multi-hop Methods. (line 39) +* su method: Inline methods. (line 62) +* sudo hop method: Multi-hop Methods. (line 52) +* sudo method: Inline methods. (line 66) +* telnet hop method: Multi-hop Methods. (line 23) +* telnet method: Inline methods. (line 58) +* tset Unix command: Remote shell setup. (line 60) +* type-ahead: Usage. (line 14) +* Unix command tset: Remote shell setup. (line 60) +* using non-standard methods: Customizing Methods. (line 6) +* using TRAMP: Usage. (line 6) +* uuencode: Inline methods. (line 18) +* Version Control: Version Control. (line 6) + + + +Tag Table: +Node: Top1363 +Node: Overview6036 +Ref: Overview-Footnote-112103 +Node: Obtaining Tramp12255 +Node: History13839 +Node: Configuration14565 +Node: Connection types16601 +Node: Inline methods18774 +Node: External transfer methods23878 +Ref: External transfer methods-Footnote-131530 +Node: Multi-hop Methods31609 +Node: Default Method34551 +Node: Customizing Methods38468 +Node: Customizing Completion38883 +Node: Password caching42296 +Node: Remote Programs43953 +Node: Remote shell setup45587 +Node: Auto-save and Backup52120 +Node: Windows setup hints54078 +Node: Usage55847 +Node: Filename Syntax57123 +Node: Multi-hop filename syntax59249 +Node: Filename completion61062 +Node: Dired62558 +Node: Compilation63027 +Node: Bug Reports63834 +Node: Frequently Asked Questions65264 +Node: Version Control70581 +Node: Version Controlled Files71723 +Node: Remote Commands72142 +Node: Changed workfiles73049 +Node: Checking out files73925 +Node: Miscellaneous Version Control74388 +Node: Remote File Ownership74814 +Node: Back-end Versions76129 +Node: Files directories and localnames77604 +Node: Localname deconstruction77939 +Node: Issues78647 +Node: Concept Index81417 + +End Tag Table diff --git a/xemacs-packages/info/tramp_ja.info b/xemacs-packages/info/tramp_ja.info new file mode 100644 index 00000000..e472d369 --- /dev/null +++ b/xemacs-packages/info/tramp_ja.info @@ -0,0 +1,2043 @@ +This is tramp_ja.info, produced by makeinfo version 4.7 from +tramp_ja.texi. + + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, +Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* TRAMP-ja: (tramp_ja). Transparent Remote Access, Multiple Protocol + Emacs remote file access via rsh and rcp + (Japanese). +END-INFO-DIR-ENTRY + + +File: tramp_ja.info, Node: Top, Next: Overview, Prev: (dir), Up: (dir) + +TRAMP version 2.0.53 ¥æ¡¼¥¶¡¼¥Þ¥Ë¥å¥¢¥ë +*************************************** + +¤³¤Î¥Õ¥¡¥¤¥ë¤Ï TRAMP version 2.0.53 ¤Ë¤Ä¤¤¤ÆÀâÌÀ¤·¤Þ¤¹¡£ TRAMP ¤Ï +XEmacs ¤Ë¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸µ¡Ç½¤òÄ󶡤¹¤ë ¥Ñ¥Ã¥±¡¼¥¸¤Ç¤¹¡£ + + TRAMP ¤Ï `Transparent Remote (file) Access, Multiple Protocol' +¤Îά¾Î¤Ç¤¹¡£¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Ï EFS ¤Î¤è¤¦¤Ê +¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸µ¡Ç½¤òÄ󶡤·¤Þ¤¹¡£ + + °Û¤Ê¤ëÅÀ¤Ï¥Õ¥¡¥¤¥ë¤ÎžÁ÷ÊýË¡¤Ç¤¹¡£EFS ¤Ï¡¢ +¥í¡¼¥«¥ë¥Û¥¹¥È¤È¥ê¥â¡¼¥È¥Û¥¹¥È´Ö¤Î¥Õ¥¡¥¤¥ëžÁ÷¤Ë FTP ¤ò»ÈÍѤ·¤Þ¤¹¡£ +°ìÊý TRAMP ¤Ï¡¢`rsh' ¤È `rcp' ¤¢¤ë¤¤¤Ï¾¤ÎƱ¤¸¤è¤¦ +¤ÊƯ¤­¤ò¤¹¤ë¥×¥í¥°¥é¥à¡¢Î㤨¤Ð `ssh' ¤ä `scp'¤ò»ÈÍѤ· ¤Þ¤¹¡£ + + ¤³¤Î¥É¥­¥å¥á¥ó¥È¤ÎºÇ¿·¥Ð¡¼¥¸¥ç¥ó¤Ï web ¥µ¥¤¥È +`http://www.freesoftware.fsf.org/tramp/' ¤Ë¤¢¤ê¤Þ¤¹¡£ + + TRAMP¤Î¤¿¤á¤Î¥á¡¼¥ê¥ó¥°¥ê¥¹¥È +, +¤¬Â¸ºß¤·¤Þ¤¹¡£¥¢¡¼¥«¥¤¥Ö¤ÏÄ̾ï¤Î Savannah ¥¢¡¼¥«¥¤¥Ö¤ÈƱ¤¸¾ì½ê¤È¡¢ +`http://www.mail-archive.com/emacs-rcp@ls6.cs.uni-dortmund.de/' +¤Ë¤¢¤ê¤Þ¤¹¡£ + + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, +Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover texts + being "A GNU Manual", and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + "GNU Free Documentation License" in the Emacs manual. + + (a) The FSF's Back-Cover Text is: "You have freedom to copy and + modify this GNU Manual, like GNU software. Copies published by + the Free Software Foundation raise funds for GNU development." + + This document is part of a collection distributed under the GNU + Free Documentation License. If you want to distribute this + document separately from the collection, you can do so by adding a + copy of the license to the document, as described in section 6 of + the license. + +* Menu: + +* Overview:: TRAMP ¤Ç²Äǽ¤Ê»ö¡¢ÉÔ²Äǽ¤Ê»ö + +¥¨¥ó¥É¥æ¡¼¥¶¡¼¸þ¤±: + +* Obtaining Tramp:: TRAMP ¤ÎÆþ¼êÊýË¡ +* History:: TRAMP ¤ÎÎò»Ë +* Configuration:: TRAMP ¤ÎÀßÄê +* Usage:: TRAMP ¤Î»È¤¤Êý +* Bug Reports:: ¥Ð¥°¤äÌäÂê¤ÎÊó¹ð +* Frequently Asked Questions:: ¤è¤¯¤¢¤ë¼ÁÌä¤È¤½¤ÎÅú +* Concept Index:: ¤½¤ì¤¾¤ì¤Î³µÇ°¤Ë¤Ä¤¤¤Æ¤Î¹àÌÜ + +³«È¯¼Ô¸þ¤±: + +* Version Control:: ¥ê¥â¡¼¥È¥Ð¡¼¥¸¥ç¥ó¥³¥ó¥È¥í¡¼¥ë¤ÎÆâÉôưºî +* Files directories and localnames:: ¥Õ¥¡¥¤¥ë̾¡¢¥Ç¥£¥ì¥¯¥È¥ê¡¢¥í¡¼¥«¥ë̾¤¬¤É¤Î¤è¤¦¤Ë + ÊÑ´¹¤µ¤ì(mangled)¡¢´ÉÍý¤µ¤ì¤ë¤« +* Issues:: µÄÏÀ¤Î;ÃϤ¬¤¢¤ëÅÀ¤È²¿¤¬·èÄꤵ¤ì¤Æ¤¤¤ë¤« + + --- ¾ÜºÙ¤Ê¥Î¡¼¥É¤Î°ìÍ÷ --- + +TRAMP ¤ÎÀßÄê + +* Connection types:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ø¤ÎÀܳ¤Î¼ïÎà +* Inline methods:: ¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É +* External transfer methods:: ³°ÉôžÁ÷¥á¥½¥Ã¥É +* Multi-hop Methods:: ¥Þ¥ë¥Á¥Û¥Ã¥×¤ò»ÈÍѤ·¤¿¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø¤ÎÀܳ +* Default Method:: ¥Ç¥Õ¥©¥ë¥È¤Î¥á¥½¥Ã¥É¤ÎÁªÂò +* Customizing Methods:: Èóɸ½à¤Î¥á¥½¥Ã¥É¤ò»È¤¦ +* Customizing Completion:: ¥æ¡¼¥¶¡¿¥Û¥¹¥È̾Êä´°¤Î¤¿¤á¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ÎÁªÂò +* Remote Programs:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç TRAMP ¤¬¥×¥í¥°¥é¥à¤òȯ¸«¡¢»ÈÍѤ¹¤ëÊýË¡ +* Remote shell setup:: ¥ê¥â¡¼¥È¥·¥§¥ëÀßÄê¤Î¥Ò¥ó¥È +* Windows setup hints:: Cygwin ssh ¤Ë¤Þ¤Ä¤ï¤ë»öÊÁ +* Auto-save and Backup:: Auto-save ¤È¥Ð¥Ã¥¯¥¢¥Ã¥× + +TRAMP ¤Î»È¤¤Êý + +* Filename Syntax:: TRAMP ¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +* Multi-hop filename syntax:: ¥Þ¥ë¥Á¥Û¥Ã¥×¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +* Filename completion:: ¥Õ¥¡¥¤¥ë̾¤ÎÊä´° +* Dired:: Dired + +¥ê¥â¡¼¥È¥Ð¡¼¥¸¥ç¥ó¥³¥ó¥È¥í¡¼¥ë¤ÎÆâÉôưºî + +* Version Controlled Files:: ¥Õ¥¡¥¤¥ë¤¬¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤ÎȽÃÇ +* Remote Commands:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥³¥Þ¥ó¥É¤Î¼Â¹Ô +* Changed workfiles:: ºî¶È¥Õ¥¡¥¤¥ë¤ÎÊѹ¹¤Îȯ¸« +* Checking out files:: ºî¶È¥Õ¥¡¥¤¥ë¤Î¥ê¥Ý¥¸¥È¥ê¤«¤é¤Î¼èÆÀ +* Miscellaneous Version Control:: ¤½¤Î¾¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Ë´Ø·¸¤¹¤ë»ö + +¤½¤Î¾¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Ë´Ø·¸¤¹¤ë»ö + +* Remote File Ownership:: VC ¤¬¥ï¡¼¥¯¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥Ê¡¼¤òÄ´¤Ù¤ëÊýË¡ +* Back-end Versions:: VC ¤¬ RCS ¤Î¥Ð¡¼¥¸¥ç¥ó¤òÄ´¤Ù¤ëÊýË¡ + +¥Õ¥¡¥¤¥ë̾¡¢¥Ç¥£¥ì¥¯¥È¥ê¡¢¥í¡¼¥«¥ë̾¤¬¤É¤Î¤è¤¦¤ËÊÑ´¹¤µ¤ì(mangled)¡¢´ÉÍý¤µ¤ì¤ë¤« + +* Localname deconstruction:: ¥í¡¼¥«¥ë̾¤ÎÍ×ÁǤؤÎʬ²ò + + +File: tramp_ja.info, Node: Overview, Next: Obtaining Tramp, Prev: Top, Up: Top + +1 TRAMP ¤Î³µÍ× +************** + +XEmacs ¤Ë TRAMP ¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¤È¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å +¤Î¥Õ¥¡¥¤¥ë¤Ë¥í¡¼¥«¥ë¥Õ¥¡¥¤¥ë¤ÈƱ¤¸¤è¤¦¤Ê´¶³Ð¤Ç¥¢¥¯¥»¥¹¤Ç¤­¤Þ¤¹¡£ +¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¥·¥¹¥Æ¥à¾å¤Î¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸¡¢¥Ð¡¼¥¸¥ç¥ó¥³¥ó¥È¥í¡¼¥ë¡¢ +`dired' ¤òÆ©²áŪ¤Ë¼Â¹Ô¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + ¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ø¤Î¥¢¥¯¥»¥¹¤Ë¤Ï¡¢`rsh' ¤ä `rlogin'¡¢ `telnet' +¥³¥Þ¥ó¥É¡¢¤¢¤ë¤¤¤Ï¤³¤ì¤é¤ËÎà»÷¤·¤¿ÀܳÊýË¡¤ò»ÈÍÑ +¤·¤Þ¤¹¡£¤³¤ì¤é¤Î¥³¥Þ¥ó¥É¤Ï ASCII ¤òÄ̲ᤵ¤»¤ë¤³¤È¤¬²Äǽ¤Ç¤Ê¤±¤ì¤Ð +¤Ê¤ê¤Þ¤»¤ó¤¬¡¢8-bit ¥¯¥ê¡¼¥ó¤Ç¤¢¤ëɬÍפϤ¢¤ê¤Þ¤»¤ó¡£ + + ¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤ÏÊ̤Υޥ·¥ó¤Ø¤Î `ssh' Àܳ¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤¹¡£ +¤³¤ì¤Ï¡¢¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Î¤â¤Ã¤È¤â°ìÈÌŪ¤Ê»È¤¤Êý¤Î¤Ò¤È¤Ä¤Ç¤¹¡£ÆÃ¤Ë +`ftp'¥¢¥¯¥»¥¹¤¬µö²Ä¤µ¤ì¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤â¡¢Â¾¤Î¥Þ¥·¥ó¤Ø¤Î +Èæ³ÓŪ¥»¥­¥å¥¢¤Ê¥¢¥¯¥»¥¹¤¬²Äǽ¤È¤Ê¤ê¤Þ¤¹¡£ + + TRAMP ¤Ë¤è¤Ã¤Æ¼Â¹Ô¤µ¤ì¤ë¥¢¥¯¥Æ¥£¥Ó¥Æ¥£¤Î¤Û¤È¤ó¤É¤Ï¡¢¥ê¥â¡¼¥È +¥í¥°¥¤¥ó¤¬²Äǽ¤Ç¡¢Ã¼Ëö¾å¤Ç¼Â¹Ô¤Ç¤­¤ë¤³¤È¤À¤±¤òÍ׵ᤷ¤Þ¤¹¡£¥ê¥â¡¼¥È +¥Õ¥¡¥¤¥ë¤Ë¥¢¥¯¥»¥¹¤¹¤ë¤¿¤á¤Ë¡¢TRAMP ¤Ï¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤ò°ì»þŪ +¤Ë¥í¡¼¥«¥ë¥Þ¥·¥ó¤ËžÁ÷¤·¤Þ¤¹¡£ + + TRAMP ¤Ï¡¢¤µ¤Þ¤¶¤Þ¤ÊÊýË¡¤Ç¥Þ¥·¥ó´Ö¤Î¥Õ¥¡¥¤¥ëžÁ÷¤ò¤ª¤³¤Ê¤¤¤Þ¤¹¡£ +žÁ÷ÊýË¡¤Ï´Êñ¤ËÁªÂò¤Ç¤­¡¢¤¢¤Ê¤¿¤Î¥Ë¡¼¥º¤È¥Þ¥·¥ó´Ä¶­¤Ë±þ¤¸¤Æ»È¤¤ +¤ï¤±¤ë»ö¤¬¤Ç¤­¤Þ¤¹¡£ + +(Â礭¤Ê¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ)¤â¤Ã¤È¤â®¤¤Å¾Á÷¥á¥½¥Ã¥É¤Ï¡¢¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤Î +žÁ÷¥Ñ¥Ã¥±¡¼¥¸¡¢¤¿¤È¤¨¤Ð `rcp'¡¢`scp'¡¢`rsync' +¤ò»È¤¦¤â¤Î¤Ç¤¹¡£¤³¤ì¤é¤Î¥á¥½¥Ã¥É¤Ï¡¢¥Õ¥¡¥¤¥ë¤Î¥³¥Ô¡¼¥³¥Þ¥ó¥É¤¬¥ê¥â¡¼¥È +¥Þ¥·¥ó¤Î¥Ñ¥¹¥ï¡¼¥É¤ò¤¿¤º¤Í¤Ê¤¤¾ì¹ç¤Ë¤Î¤ßÍ­¸ú¤Ç¤¹¡£ + + ¤â¤·¡¢¥ê¥â¡¼¥È¥³¥Ô¡¼¥á¥½¥Ã¥É¤¬»È¤¨¤Ê¤¤¾ì¹ç¤Î¤¿¤á¤Ë¡¢TRAMP ¤Ï¡¢ +¥·¥§¥ë¤òľÀÜÍøÍѤ·¤¿É乿²½Å¾Á÷ÊýË¡¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤¹¡£¤³¤ÎÊýË¡¤ò»È¤¦ +¤¿¤á¤Ë¤Ï¡¢`mimencode' ¤« `uuencode' ¤¬¥ê¥â¡¼¥È¥Þ¥·¥ó +¾å¤Ë¸ºß¤·¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£¤³¤ì¤é¤Ï°ìÈ̤˾®¤µ¤Ê¥Õ¥¡¥¤¥ë¤ËÂФ·¤ÆÂ®¤¤ +ÊýË¡¤Ç¤¹¡£ + + ¾åµ­¤ÎÀ©¸ÂÆâ¤Ç¤¢¤ì¤Ð¡¢TRAMP ¤ÏÈó¾ï¤Ë¥Ñ¥ï¥Õ¥ë¤Ç¤¹¡£¤¿¤À¤·¡¢Ãí°Õ¤·¤Æ +¤ª¤«¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤Î¤Ï¡¢¸½ºß¤Î TRAMP ¤Ï¡¢¥¨¥ó¥É¥æ¡¼¥¶¡¼¸þ¤±¤ÎÀöÎý +¤µ¤ì¤¿À½ÉʤȤϤۤɱ󤤾õÂ֤Ǥ¢¤ë¤È¤¤¤¦¤³¤È¤Ç¤¹¡£¤â¤¦¤·¤Ð¤é¤¯¤Î´Ö¤Ï¡¢»þ¡¹ +¤Á¤ç¤Ã¤Èº¤¤Ã¤¿»ö¤Ë¤Ê¤Ã¤¿¤ê¡¢¥³¡¼¥É¤ËÌäÂ꤬¤¢¤ë¤«¤â¤·¤ì¤Ê¤¤¤È¤¤¤¦¤³¤È¤ò +ǰƬ¤Ë¤ª¤¤¤Æ¤ª¤¤¤Æ¤¯¤À¤µ¤¤¡£ + +¤¹¤Ç¤Ë³«È¯¼Ô¤¬Æü¡¹¤Îºî¶È¤Ë»È¤¦»ö¤¬¤Ç¤­¤ëÄøÅ٤ˤϰÂÄꤷ¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¡¢ +¥¤¥ó¥¹¥È¡¼¥ë¤ÈÀßÄê¤ò³Ð¤¨¤ë¤Î¤Ï¡¢ÀìÌçÍѸì¤Î¤»¤¤¤Ç¼ã´³Æñ¤·¤¤¤Ç¤·¤ç¤¦¡£ + + TRAMP ¤Ï¡¢¤Þ¤À¥¢¥¯¥Æ¥£¥Ö¤Ë³«È¯¤ò¤·¤Æ¤¤¤ëºÇÃæ¤Ç¤¹¡£¤·¤¿¤¬¤Ã¤Æ¡¢¤É¤ó¤Ê +º³ºÙ¤ÊÌäÂê¤Ç¤¢¤Ã¤Æ¤â¡¢¤¼¤Ò TRAMP ³«È¯¼Ô¤ËÊó¹ð¤·¤Æ¤¯¤À¤µ¤¤¡£ *Note Bug +Reports::. + +ÉñÂæ¤Î΢¦ +.......... + +¤³¤Î¥»¥¯¥·¥ç¥ó¤Ç¤Ï¡¢TRAMP ¤ò»È¤¤¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤Ë¥¢¥¯¥»¥¹¤·¤¿»þ¤Ë¡¢ +ÉñÂæ¤Î΢¦¤Ç²¿¤¬¤ª¤³¤Ã¤Æ¤¤¤ë¤«¤òÀâÌÀ¤·¤Þ¤¹¡£ + + `C-x C-f' ¤È¥¿¥¤¥×¤·¡¢TRAMP ¤Î¥Õ¥¡¥¤¥ë̾¤Î°ìÉô¤òÆþÎϤ·¤Þ¤¹¡£ +¤½¤ì¤«¤é¡¢¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤Î¤¿¤á¤Ë `' ¤ò²¡¤·¤Þ¤¹¡£¤³¤ì +¤¬¤½¤Î¥Û¥¹¥È¤ËÂФ¹¤ë½é¤á¤Æ¤Î TRAMP ¤Îµ¯Æ°¤Î¾ì¹ç¡¢°Ê²¼¤Î¤è¤¦¤Ê»ö +¤¬¤ª¤³¤ê¤Þ¤¹¡£ + + * TRAMP ¤Ï¡¢Â¾¤Î¥Û¥¹¥È¤Ø¤ÎÀܳ¤¬É¬Íפʻö¤òǧ¼±¤·¤Þ¤¹¡£¤½¤ì¤«¤é + `telnet HOST' ¤« `rsh HOST -l USER' ¤¢¤ë¤¤ + ¤Ï¡¢¤½¤Î¾¤Î¥ê¥â¡¼¥È¥Û¥¹¥È¤ØÀܳ¤¹¤ë¤¿¤á¤Î¥Ä¡¼¥ë¤òµ¯Æ°¤·¤Þ¤¹¡£¤³¤ì¤é¤Î + ¥×¥í¥»¥¹¤È¤Î¥³¥ß¥å¥Ë¥±¡¼¥·¥ç¥ó¤Ï XEmacs ¤Î¥Ð¥Ã¥Õ¥¡¤ò·Ðͳ¤· + ¤Æ¤ª¤³¤Ê¤ï¤ì¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ¡¢¥ê¥â¡¼¥È¦¤«¤é¤Î½ÐÎϤϤ³¤Î¥Ð¥Ã¥Õ¥¡¤Ë½ÐÎÏ + ¤µ¤ì¤Þ¤¹¡£ + + * ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ï¡¢¥í¥°¥¤¥ó̾¤Î¥×¥í¥ó¥×¥È¤òɽ¼¨¤·¤Þ¤¹(`telnet' + ¤Î¾ì¹ç)¡£¥í¥°¥¤¥ó̾¤ÏÆþÎϤµ¤ì¤¿¥Õ¥¡¥¤¥ë̾¤Ë´Þ¤Þ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢TRAMP + ¤Ï¥í¥°¥¤¥ó̾¤È²þ¹Ô¤òÁ÷¿®¤·¤Þ¤¹¡£ + + * ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ï¡¢¥Ñ¥¹¥ï¡¼¥É¤¢¤ë¤¤¤Ï¥Ñ¥¹¥Õ¥ì¡¼¥º¤Î¥×¥í¥ó¥×¥È¤òɽ¼¨ + ¤·¤Þ¤¹(¤³¤ì¤Ï`rsh' ¤Î¾ì¹ç¤Ç¤¹¡£`telnet' ¤Î¾ì¹ç¤Ï¥í¥° + ¥¤¥ó̾¤òÁ÷¿®¤·¤¿¸å¤Ëɽ¼¨¤µ¤ì¤Þ¤¹)¡£TRAMP ¤Ï¥ß¥Ë¥Ð¥Ã¥Õ¥¡¤Ë¥×¥í¥ó + ¥×¥È¤òɽ¼¨¤·¡¢¥Ñ¥¹¥ï¡¼¥É¤Þ¤¿¤Ï¥Ñ¥¹¥Õ¥ì¡¼¥º¤ò¤¿¤º¤Í¤Þ¤¹¡£ + + ¥Ñ¥¹¥ï¡¼¥É¤«¥Ñ¥¹¥Õ¥ì¡¼¥º¤òÆþÎϤ¹¤ë¤È¡¢TRAMP ¤Ï¤½¤ì¤ò¥ê¥â¡¼¥È¥Û¥¹¥È + ¤ËÁ÷¿®¤·¡¢¼¡¤Ë²þ¹Ô¤òÁ÷¿®¤·¤Þ¤¹¡£ + + * TRAMP ¤Ï¡¢¥·¥§¥ë¥×¥í¥ó¥×¥È¤«¥í¥°¥¤¥ó¤Ë¼ºÇÔ¤·¤¿»Ý¤Î¥á¥Ã¥»¡¼¥¸¤òÂÔ¤Á + ¤Þ¤¹¡£ + + ¤â¤·¡¢TRAMP + ¤¬¡¢°ìÄê»þ´Ö(¤¿¤È¤¨¤Ð°ìʬ)ÂԤäƤ⡢¤³¤ì¤é¤Î¥á¥Ã¥»¡¼¥¸¤ò + ȯ¸«¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤«¤Ã¤¿¤é¡¢¥ê¥â¡¼¥È¥·¥§¥ë¤Î¥×¥í¥ó¥×¥È¤òȯ¸«¤Ç¤­¤Ê¤«¤Ã + ¤¿»Ý¤Î¥á¥Ã¥»¡¼¥¸¤ò½ÐÎϤ·¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤«¤éÁ÷¿®¤µ¤ì¤¿¥á¥Ã¥»¡¼¥¸¤òɽ¼¨ + ¤·¤Þ¤¹¡£ + + ¤â¤·¡¢TRAMP ¤¬ `login failed' ¤È¤¤¤¦¥á¥Ã¥»¡¼¥¸¤òȯ¸«¤·¤¿¤é¡¢¤½¤ì¤ò + ɽ¼¨¤·¡¢¥í¥°¥¤¥ó¤òÃæ»ß¤·¤Þ¤¹¡£¤³¤ì¤ÇºÆ¤Ó¥í¥°¥¤¥ó¤ò»î¤ß¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + * ¥í¥°¥¤¥ó¤ËÀ®¸ù¤·¡¢TRAMP + ¤¬¥·¥§¥ë¥×¥í¥ó¥×¥È¤òȯ¸«¤·¤¿¤È¤·¤Þ¤¹¡£¤³¤³¤Ç¡¢ TRAMP ¤Ï `/bin/sh' + ¤òµ¯Æ°¤·¤Þ¤¹¡£¤³¤ì¤Ï¡¢Bourne ¥·¥§¥ë¤È C + ¥·¥§¥ë¤Ç¤Ïʸˡ¤¬°Û¤Ê¤ë¤¿¤á¤Ç¤¹¡£(1) + + Bourne ¥·¥§¥ë¤¬µ¯Æ°¤µ¤ì¤¿¤é¡¢TRAMP + ¤Ï³Î¼Â¤Ëưºî¤¹¤ë´Ä¶­¤ò½àÈ÷¤¹¤ë¤¿¤á + ¤Ë¤¤¤¯¤Ä¤«¤Î¥³¥Þ¥ó¥É¤òÁ÷¿®¤·¤Þ¤¹¡£echo + ¤ò¥ª¥Õ¤Ë¤·¡¢¥·¥§¥ë¥×¥í¥ó¥×¥È¤òÀßÄê + ¤·¤¿¤ê¡¢¤½¤Î¾¤¤¤¯¤Ä¤«¤Î»ö¤ò¤ª¤³¤Ê¤¤¤Þ¤¹¡£ + + * + ¤µ¤Æ¡¢¥ê¥â¡¼¥È¥·¥§¥ë¤¬µ¯Æ°¤µ¤ì¤­¤Á¤ó¤Èưºî¤¹¤ë¾õÂ֤ˤʤê¤Þ¤·¤¿¡£¤³¤³¤Ç¡¢ + ²¿¤¬¤ª¤³¤ë¤Ï¤º¤À¤Ã¤¿¤«»×¤¤¤À¤·¤Æ¤¯¤À¤µ¤¤¡£¥ê¥â¡¼¥È¥Û¥¹¥È¾å¤Ë¤É¤Î¤è¤¦¤Ê + ¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¤ò TRAMP + ¤¬Ä´¤Ù¡¢¥Õ¥¡¥¤¥ë̾¤òÊä´°¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤ë ¤³¤È¤Ç¤¹¡£ + + TRAMP ¤Ï `cd' ¤È `ls' ¥³¥Þ¥ó¥É¡¢¤½¤·¤Æ»þ¡¹ globbing ¤µ¤ì¤¿ `echo' + ¤ò¼Â¹Ô¤·¤Þ¤¹¡£¤³¤ì°Ê³°¤Ë¡¢¥Õ¥¡¥¤¥ë¤¬½ñ¤­¹þ¤ß²Äǽ + ¤«¤É¤¦¤«¡¢¥Ç¥£¥ì¥¯¥È¥ê¤«¤É¤¦¤«Åù¤òÄ´¤Ù¤ë¤¿¤á¤Ë `test' ¤¬¡¢¤·¤Ð + ¤·¤Ð»ÈÍѤµ¤ì¤Þ¤¹¡£¥ª¥Ú¥ì¡¼¥·¥ç¥ó¤ò¤ª¤³¤Ê¤¦¤¿¤á¤Ë¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Î½Ð + ÎϤϥѡ¼¥¹¤µ¤ì¤Þ¤¹¡£ + + * ¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤¬´°Î»¤·¡¢`C-xC-f'¤È´°Á´¤Ê¥Õ¥¡¥¤¥ë̾¤òÆþÎϤ·¡¢ + `' ¤ò²¡¤·¤¿¤È¤·¤Þ¤·¤ç¤¦¡£¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë¤¿¤á¤Ë¡¢¥ê¥â¡¼¥È + ¥Û¥¹¥È¤«¤é¥í¡¼¥«¥ë¥Û¥¹¥È¤Ë¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤òžÁ÷¤¹¤ë»þ¤¬¤è¤¦¤ä¤¯¤ä¤Ã¤Æ + ¤­¤Þ¤·¤¿¡£ + + TRAMP + ¤¬¤É¤Î¤è¤¦¤Ë¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤òžÁ÷¤¹¤ë¤Î¤«¤È¤¤¤¦ÀâÌÀ¤Ï¡¢¾å¤ò¸«¤Æ + ¤¯¤À¤µ¤¤¡£ + + ¥¤¥ó¥é¥¤¥óžÁ÷¤Î¤¿¤á¤Ë¡¢TRAMP ¤Ï `mimencode -b + /path/to/remote/file' + ¤Î¤è¤¦¤Ê¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤·¡¢½ÐÎϤ¬¥³¥ß¥å¥Ë¥±¡¼¥·¥ç¥ó¤Î¤¿¤á¤Î¥Ð¥Ã¥Õ¥¡¤Ë + ÃßÀѤµ¤ì¤ë¤Þ¤ÇÂÔ¤Á¤Þ¤¹¡£¤½¤·¤Æ¡¢¥Õ¥¡¥¤¥ë¤ÎÃæ¿È¤òºîÀ®¤¹¤ë¤¿¤á¤Ë¡¢½ÐÎϤò + Éü¹æ²½¤·¤Þ¤¹¡£ + + out-of-band žÁ÷¤Î¤¿¤á¤Ë¡¢TRAMP ¤Ï°Ê²¼¤Î¤è¤¦¤Ê¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤·¤Þ¤¹: + rcp user@host:/path/to/remote/file /tmp/tramp.4711 + ¤½¤·¤Æ¡¢¥í¡¼¥«¥ë¤Ê°ì»þ¥Õ¥¡¥¤¥ë `/tmp/tramp.4711' ¤ò¥Ð¥Ã¥Õ¥¡¤ËÆÉ¤ß + ¹þ¤ß¡¢°ì»þ¥Õ¥¡¥¤¥ë¤òºï½ü¤·¤Þ¤¹¡£ + + * + º£¡¢¤¢¤Ê¤¿¤Ï¥Ð¥Ã¥Õ¥¡¤ÎÆâÍÆ¤òÊÔ½¸¤·¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¡¢¹¬±¿¤Ë¤âÉñÂæÎ¢¤Ç²¿¤¬ + ¤ª¤³¤Ã¤Æ¤¤¤ë¤Î¤«¤Ëµ¤¤¬¤Ä¤­¤Þ¤»¤ó(¤³¤Î¥»¥¯¥·¥ç¥ó¤òÆÉ¤à¤Þ¤Ç¤Ï¡¢¤½¤¦¤Ç¤·¤ç¤¦)¡£ + ºî¶È¤¬½ª¤ê¡¢¥Ð¥Ã¥Õ¥¡¤òÊݸ¤¹¤ë¤¿¤á¤Ë `C-x C-s' ¤ò²¡¤·¤Þ¤¹¡£ + + * ºÆ¤Ó¡¢TRAMP ¤Ï¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤ò¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥¤¥ó¥é¥¤¥ó¤« + out-of-band + ¥á¥½¥Ã¥É¤ÇžÁ÷¤·¤Þ¤¹¡£¤³¤³¤Ç¤Ï¥Õ¥¡¥¤¥ë¤òÆÉ¤ß»þ¤Ë¤ª¤³¤Ã¤Æ¤¤¤ë»ö¤ÈµÕ¤Î¤³¤È + ¤¬¤ª¤³¤Ã¤Æ¤¤¤Þ¤¹¡£ + + + ¤³¤ÎÀâÌÀ¤Ç¡¢TRAMP +¤ò»È¤¤¥Õ¥¡¥¤¥ë¤ò¥ª¡¼¥×¥ó¤·¤¿»þ¤ËÉñÂæÎ¢¤Ç¤ª¤³¤Ã¤Æ¤¤¤ë +»ö¤ò¤ï¤«¤Ã¤Æ¤â¤é¤¨¤ë¤³¤È¤ò´ê¤Ã¤Æ¤¤¤Þ¤¹¡£ + + ---------- Footnotes ---------- + + (1) ¥í¥°¥¤¥ó¥·¥§¥ë¤¬ `exec /bin/sh' ¤òÀµ¤·¤¤¥³¥Þ¥ó¥É¤È¤·¤ÆÇ§¼±¤»¤º¤Ë +`/bin/sh' ¤Îµ¯Æ°¤Ë¼ºÇÔ¤¹¤ë¤³¤È¤¬¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤¿¤Ö¤ó¡¢¤¢¤Ê¤¿¤Ï +Scheme ¥·¥§¥ë `scsh' ¤ò»È¤Ã¤Æ¤¤¤ë¤Î¤Ç¤·¤ç¤¦... + + +File: tramp_ja.info, Node: Obtaining Tramp, Next: History, Prev: Overview, Up: Top + +2 Tramp ¤ÎÆþ¼êÊýË¡ +****************** + +TRAMP ¤Ï¡¢¥¤¥ó¥¿¡¼¥Í¥Ã¥È¾å¤Ç¥Õ¥ê¡¼¤ËÇÛÉÛ¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ºÇ¿·ÈÇ¤Ï +`http://savannah.nongnu.org/download/tramp/' +¤«¤é¥À¥¦¥ó¥í¡¼¥É²Äǽ¤Ç¤¹¡£¤³¤ÎÃæ¤Ë¤Ï¡¢¥¤¥ó¥¹¥È¡¼¥ë¤ËɬÍ×¤Ê TRAMP +¤Î¤¹¤Ù¤Æ¤Î¥É¥­¥å¥á¥ó¥È¤È¥½¡¼¥¹¥³¡¼¥É¤¬´Þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¡¢Emacs +(21.4 ¤«¤½¤ì°Ê¹ß¤Î¤â¤Î) ¤Ï¡¢TRAMP ¤ò´Þ¤ó¤Ç¤ª¤ê¡¢XEmacs ¤Ë¤â TRAMP +¤Î¥Ñ¥Ã¥±¡¼¥¸¤¬¤¢¤ê¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤é¤ò»È¤¦Êý¤¬¤¿¤Ö¤ó´Êñ¤Ç¤·¤ç¤¦¡£ +¤·¤«¤·¡¢¤â¤·ºÇ¿·¤Î³«È¯ÈǤòµá¤á¤ë¤Î¤Ç¤¢¤ì¤Ð¡¢Â³¤­¤òÆÉ¤ó¤Ç²¼¤µ¤¤...... + + ËÁ¸±²È¤Î¤¿¤á¤Ë TRAMP ¤Ï CVS ¤«¤é¤âÆþ¼ê²Äǽ¤Ç¤¹¡£CVS ¤«¤éÆþ¼ê¤·¤¿ +¥Ð¡¼¥¸¥ç¥ó¤Ï¥½¡¼¥¹¥³¡¼¥É¤ÎºÇ¿·¥Ð¡¼¥¸¥ç¥ó¤Ç¤¹¡£¤·¤¿¤¬¤Ã¤Æ¡¢ÉÔ´°Á´¤Ê +µ¡Ç½¤ä¿·¤¿¤ÊÌäÂê¤ò¤«¤«¤¨¤Æ¤¤¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤Ï¼«Ê¬ +¤ÎÀÕǤ¤Ç»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤¡£ + + TRAMP ¤ÎºÇ¿·¤Î³«È¯¥Ð¡¼¥¸¥ç¥ó¤ò CVS ¤«¤éÆþ¼ê¤¹¤ëÊýË¡¤Ï¡¢°Ê²¼¤Ë¼¨¤¹ +Savannah ¥×¥í¥¸¥§¥¯¥È¥Ú¡¼¥¸¤Ë¹Ô¤Ã¤Æ°ìÈÖ¾å¤Î¥Ê¥Ó¥²¡¼¥·¥ç¥ó¥Ð¡¼¤Ë¤¢¤ë CVS +¤Î¥ê¥ó¥¯¤ò¥¯¥ê¥Ã¥¯¤¹¤ì¤Ð¸«¤ë¤³¤È¤¬½ÐÍè¤Þ¤¹¡£ + +`http://savannah.gnu.org/projects/tramp/' + +¤â¤·¤¯¤Ï¡¢°Ê²¼¤Î¥»¥Ã¥·¥ç¥ó¤ÎÎã¤Ë½¾¤Ã¤Æ²¼¤µ¤¤¡£ + + ] *cd ~/xemacs* + ] *cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/tramp login* + + CVS password: *(just hit RET here)* + ... + + ] *cvs -z3 -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/tramp co tramp* + + ¤³¤ì¤Ç¡¢TRAMP ¤ÎºÇ¿·¥Ð¡¼¥¸¥ç¥ó¤¬´Þ¤Þ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê `~/xemacs/tramp' +¤¬ºîÀ®¤µ¤ì¤ë¤Ï¤º¤Ç¤¹¡£°Ê²¼¤Î¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤¹¤ë¤³¤È¤Ë¤è¤ê¡¢ºÇ¿·¤Î¥Ð¡¼¥¸¥ç¥ó +¤Ë¹¹¿·¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹: + + ] *cd ~/xemacs/tramp* + ] *cvs update -d* + +CVS ¥ê¥Ý¥¸¥È¥ê¤«¤é¥Õ¥¡¥¤¥ë¤ò¹¹¿·¤·¤¿¤é¡¢¿·¤·¤¤ `configure' ¥¹¥¯¥ê¥×¥È +¤òÀ¸À®¤¹¤ë¤¿¤á¤Ë `autoconf' ¤ò¼Â¹Ô¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹: + + ] *cd ~/xemacs/tramp* + ] *autoconf* + + +File: tramp_ja.info, Node: History, Next: Configuration, Prev: Obtaining Tramp, Up: Top + +3 TRAMP ¤ÎÎò»Ë +************** + +TRAMP ¤Î³«È¯¤Ï 1998 ǯ¤Î 11·î²¼½Ü¤Ë»Ï¤Þ¤ê¤Þ¤·¤¿¡£¤½¤ÎÅö»þ¤Ï¡¢¤³¤Î +¥Ñ¥Ã¥±¡¼¥¸¤Ï `rssh.el' ¤È¸Æ¤Ð¤ì¤Æ¤¤¤Þ¤·¤¿¡£¥Õ¥¡¥¤¥ë¤Ë¥¢¥¯¥»¥¹¤¹¤ë¤¿¤á +¤Î¤¿¤Ã¤¿¤Ò¤È¤Ä¤Î¥á¥½¥Ã¥É¤¬¤¢¤ë¤À¤±¤Ç¡¢`ssh' ¤ò»ÈÍѤ·¥ê¥â¡¼¥È +¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤·¡¢`scp' ¤Ç¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤òžÁ÷¤·¤Æ¤¤¤Þ¤·¤¿¡£ +¤·¤Ð¤é¤¯¤·¤Æ¡¢Ì¾Á°¤¬ `rcp.el' ¤ËÊѤï¤ê¡¢º£¤Ï TRAMP ¤È¸Æ¤Ð¤ì¤Æ¤¤¤Þ¤¹¡£ +¤³¤ì¤Ëȼ¤¤¡¢¥ê¥â¡¼¥È¥·¥§¥ë¤òµ¯Æ°¤·¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤òžÁ÷¤¹¤ë¿¤¯¤Î¥á¥½¥Ã¥É +¤¬Äɲ䵤ì¤Þ¤·¤¿¡£¤Þ¤¿¡¢VC ¥µ¥Ý¡¼¥È¤âÄɲ䵤ì¤Þ¤·¤¿¡£ + +¤â¤Ã¤È¤âºÇ¶á¤ÎÂ礭¤Êµ¡Ç½Äɲäϡ¢2000ǯ4·î¤Î¥Þ¥ë¥Á¥Û¥Ã¥×¥á¥½¥Ã¥É¤ÎÄɲäȡ¢ +2002ǯ7·î¤Î TRAMP ¤Ë¤ª¤±¤ë¥Õ¥¡¥¤¥ë̾¤È Ange-FTP ¤Ë¤ª¤±¤ë¥Õ¥¡¥¤¥ë̾¤Î +Åý°ì¤Ç¤¹¡£ + + +File: tramp_ja.info, Node: Configuration, Next: Usage, Prev: History, Up: Top + +4 TRAMP ¤ÎÀßÄê +************** + +TRAMP ¤Ï(Ä̾ï)¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¤À¤±¤Ç´°Á´¤Ëµ¡Ç½¤·¤Þ¤¹¡£½é´ü¾õÂ֤Ǥϡ¢ +¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø¤ÎÀܳ¤Ë `ssh' ¥×¥í¥°¥é¥à¤ò»ÈÍѤ·¡¢base64 ¥¨¥ó +¥³¡¼¥Ç¥£¥ó¥°¤â¤·¤¯¤Ï uu ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò»ÈÍѤ¹¤ë¤è¤¦¤ËÀßÄꤵ¤ì¤Æ¤¤¤Þ +¤¹¡£ ½¾¤Ã¤ÆºÇ¤â´Êñ¤Ê¾ì¹ç¤Ë¤Ï `C-x C-f' ¤ÈÂǤÁ¹þ¤ó¤Ç¥Õ¥¡¥¤¥ë̾ +`/[USER@MACHINE]/PATH/TO.FILE'. ¤òÆþÎϤ¹¤ë¤À¤±¤Ç¤¹¡£ + +¥Û¥¹¥È¤Ë¤è¤Ã¤Æ¤Ï¡¢Àܳ¤ò³ÎΩ¤¹¤ë¤Î¤ËÌäÂ꤬µ¯¤­¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£¤³¤ì¤Ï¡¢ +remote shell ¤Î¿¶¤ëÉñ¤¤¤Ë¤è¤ë¤â¤Î¤Ç¤¹¡£¤³¤Î¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï *Note Remote +shell setup::, ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£ + +¤â¤·¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤È¤ÎÀܳ¤Ë¤³¤ì¤é¤Î¥³¥Þ¥ó¥É¤ò»ÈÍѤ·¤¿¤¯¤Ê¤¤¾ì¹ç¤Ï¡¢ +TRAMP ¤Î¥Ç¥Õ¥©¥ë¥È¤ÎÀܳ¤ÈžÁ÷¥á¥½¥Ã¥É¤òÊѹ¹¤·¤Æ¤¯¤À¤µ¤¤¡£¥ê¥â¡¼¥È +¥Þ¥·¥ó¤ËÀܳ¤·¥Õ¥¡¥¤¥ë¤òžÁ÷¤¹¤ë¤Î¤Ë»È¤¦¤³¤È¤Î¤Ç¤­¤ë TRAMP ¤Î¥á¥½¥Ã¥É +¤¬¤¤¤¯¤Ä¤«¤¢¤ê¤Þ¤¹ (*note Connection types::)¡£ + + ¤É¤Î¥á¥½¥Ã¥É¤¬¤Õ¤µ¤ï¤·¤¤¤«¤ï¤«¤é¤Ê¤¤¤Ê¤é¼¡¤ò¸«¤Æ²¼¤µ¤¤: *Note +Default Method::. + +* Menu: + +* Connection types:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ø¤ÎÀܳ¤Î¼ïÎà +* Inline methods:: ¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É +* External transfer methods:: ³°ÉôžÁ÷¥á¥½¥Ã¥É +* Multi-hop Methods:: ¥Þ¥ë¥Á¥Û¥Ã¥×¤ò»ÈÍѤ·¤¿¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø¤ÎÀܳ +* Default Method:: ¥Ç¥Õ¥©¥ë¥È¤Î¥á¥½¥Ã¥É¤ÎÁªÂò + ¤³¤³¤Ç¤Ï¤É¤Î¥á¥½¥Ã¥É¤ò»È¤¨¤Ð¤è¤¤¤« + ¤ï¤«¤é¤Ê¤¤¿Í¤Î¤ª¼êÅÁ¤¤¤â¤·¤Þ¤¹¡£ +* Customizing Methods:: Èóɸ½à¤Î¥á¥½¥Ã¥É¤ò»È¤¦ +* Customizing Completion:: ¥æ¡¼¥¶/¥Û¥¹¥È̾Êä´°¤Î¤¿¤á¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ÎÁªÂò +* Remote Programs:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç TRAMP ¤¬¥×¥í¥°¥é¥à¤òȯ¸«¡¢»ÈÍѤ¹¤ëÊýË¡ +* Remote shell setup:: ¥ê¥â¡¼¥È¥·¥§¥ëÀßÄê¤Î¥Ò¥ó¥È +* Windows setup hints:: Cygwin ssh ¤Ë¤Þ¤Ä¤ï¤ë»öÊÁ +* Auto-save and Backup:: Auto-save ¤È¥Ð¥Ã¥¯¥¢¥Ã¥× + + +File: tramp_ja.info, Node: Connection types, Next: Inline methods, Up: Configuration + +4.1 ¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ø¤ÎÀܳ¤Î¼ïÎà +================================ + +žÁ÷¥á¥½¥Ã¥É¤Ë¤ÏÆó¤Ä¤Î´ðËÜŪ¤Ê¥¿¥¤¥×¤¬¤¢¤ê¡¢¤½¤ì¤¾¤ì¤ËĹ½ê¡¢Ã»½ê¤¬ +¤¢¤ê¤Þ¤¹¡£Î¾¼Ô¤È¤â¤Ë¡¢`rsh' ¤ä `ssh'¡¢`telnet' +¤Î¤è¤¦¤Ê¥ê¥â¡¼¥È¥·¥§¥ë¤Ë¥¢¥¯¥»¥¹¤¹¤ë¥×¥í¥°¥é¥à¤ò»ÈÍѤ·¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó +¤ËÀܳ¤·¤Þ¤¹¡£ + + ¤³¤Î¥³¥Í¥¯¥·¥ç¥ó¤Ï¡¢TRAMP ¤¬¥í¡¼¥«¥ë¥Þ¥·¥ó¤«¤é¥ê¥â¡¼¥È¥Þ¥·¥ó¤ØÆ©²áŪ +¤Ë¥¢¥¯¥»¥¹¤¹¤ë¤¿¤á¤Ë¡¢¤µ¤Þ¤¶¤Þ¤Ê¥ª¥Ú¥ì¡¼¥·¥ç¥ó¤ò¤ª¤³¤Ê¤¦¤¿¤á¤Ë»È¤ï¤ì¤Þ¤¹¡£ +¥Õ¥¡¥¤¥ë¤ò¥ª¡¼¥×¥ó¤·¤¿»þ¤Î¥á¥½¥Ã¥É¤¬°Û¤Ê¤ë¤À¤±¤Ç¤¹¡£ + +¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤òÆÉ¤ß¹þ¤ó¤À¤ê¡¢Êݸ¤¹¤ë»þ¤Ë¤Ï¡¢Æó¤Ä¤Î¥Þ¥·¥ó´Ö¤Ç¥Õ¥¡¥¤¥ë +¤ÎÆâÍÆ¤òžÁ÷¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤Ï¡¢¥Þ¥·¥ó¤Ë¥í¥°¥¤¥ó¤·¤¿¤Î +¤ÈƱ¤¸¥³¥Í¥¯¥·¥ç¥ó¤«¡¢`rcp' ¤ä `scp'¡¢`rsync' +¤Ê¤É¤Î¥ê¥â¡¼¥È¥³¥Ô¡¼¥×¥í¥°¥é¥à¤ò»ÈÍѤ·¤¿Ê̤Υ³¥Í¥¯¥·¥ç¥ó¤ÇžÁ÷¤µ¤ì¤Þ¤¹¡£ +Á°¼Ô¤Ï "¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É"¡¢¸å¼Ô¤Ï "out-of-band ¥á¥½¥Ã¥É" ¤¢¤ë¤¤¤Ï +"³°ÉôžÁ÷¥á¥½¥Ã¥É" (ά¤·¤Æ "³°Éô¥á¥½¥Ã¥É") ¤È¤è¤Ð¤ì¤Þ¤¹¡£ + + ¾¯¤Ê¤¯¤È¤âÂ礭¤Ê¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ¤Ï¡¢°ìÈ̤˳°ÉôžÁ÷¥á¥½¥Ã¥É¤ÎÀ­Ç½¤Ï +¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤è¤ê¤¹¤°¤ì¤Æ¤¤¤Þ¤¹¡£¤½¤ÎÍýͳ¤Ï¡¢¥¤¥ó¥é¥¤¥óžÁ÷¤Ç¤Ï +¥Ç¡¼¥¿¤ÎÉ乿²½¡¢Éü¹æ²½¤ò¤ª¤³¤Ê¤¦É¬Íפ¬¤¢¤ë¤«¤é¤Ç¤¹¡£ + + ¤³¤Î¥ë¡¼¥ë¤ÎÍ£°ì¤ÎÎã³°¤Ï¡¢`scp' ¤ò»ÈÍѤ¹¤ëžÁ÷¥á¥½¥Ã¥É¤Ç¤¹¡£ +¤³¤ì¤é¤Î¥á¥½¥Ã¥É¤Î¼ÂºÝ¤Î¥Õ¥¡¥¤¥ëžÁ÷¤ÎÀ­Ç½¤Ï¹â¤¤¤Î¤Ç¤¹¤¬¡¢Å¾Á÷³«»Ï»þ +¤Î°Å¹æ²½¤Ë¤«¤«¤ï¤ë¥Í¥´¥·¥¨¡¼¥·¥ç¥ó¤Î¥ª¡¼¥Ð¡¼¥Ø¥Ã¥É¤¬¥Õ¥¡¥¤¥ëžÁ÷¤ÎÀ­Ç½ +¤òÄ¢¾Ã¤·¤Ë¤·¤Þ¤¹¡£ + +³°ÉôžÁ÷¥á¥½¥Ã¥É¤ò»È¤¦¤¿¤á¤Ë¤Ï¡¢¥ê¥â¡¼¥È¥³¥Ô¡¼¥³¥Þ¥ó¥É¤¬ÂÐÏÃŪ¤Ç¤Ê¤¤¡¢ +¤Ä¤Þ¤ê¥³¥Þ¥ó¥É¤¬¥Ñ¥¹¥ï¡¼¥É¤Î¤¿¤á¤Ë¥×¥í¥ó¥×¥È¤ò½ÐÎϤ·¤Ê¤¤¤³¤È¤¬É¬ÍפǤ¹¡£ +¤â¤·¡¢¥Ñ¥¹¥ï¡¼¥ÉÆþÎϤʤ·¤Î¥ê¥â¡¼¥È¥³¥Ô¡¼¥³¥Þ¥ó¥É¤ò»È¤¦»ö¤¬¤Ç¤­¤Ê¤¤¤Î¤Ç +¤¢¤ì¤Ð¡¢¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤ò»È¤¦É¬Íפ¬¤¢¤ê¤Þ¤¹¡£ + + ¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤Î°ì¼ï¤Ë¡¢"¥Þ¥ë¥Á¥Û¥Ã¥×¥á¥½¥Ã¥É" ¤¬¤¢¤ê¤Þ¤¹¡£ +¤³¤Î¥á¥½¥Ã¥É¤ò»È¤¦¤È¡¢¤¤¤¯¤Ä¤«¤Î¥Û¥Ã¥×¤ò»È¤¤¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤ØÀܳ +¤Ç¤­¤Þ¤¹¡£¤³¤ì¤Ï¡¢¤¢¤Ê¤¿¤¬¥»¥­¥å¥¢¤Ê¥Í¥Ã¥È¥ï¡¼¥¯¤ÎÃæ¤Ë¤¤¤Æ¡¢Í׺ɥۥ¹¥È +¤ò·Ðͳ¤·¤Æ³°Éô¤ËÀܳ¤¹¤ë¾ì¹ç¤ËÊØÍø¤Ç¤¹¡£ + + +File: tramp_ja.info, Node: Inline methods, Next: External transfer methods, Prev: Connection types, Up: Configuration + +4.2 ¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É +====================== + +TRAMP ¤Î¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤ÏÂçÊѶ¯ÎϤǡ¢³°ÉôžÁ÷¥á¥½¥Ã¥É¤ò»È¤¦»ö¤¬ +¤Ç¤­¤Ê¤¤¾õ¶·¤Ç¤âưºî¤·¤Þ¤¹¡£¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤Ï¡¢telnet ·Ðͳ¤Ç¥ê¥â¡¼¥È +¥Þ¥·¥ó¤ËÀܳ¤·¤Æ¤¤¤ë»þ¤Ëưºî¤¹¤ëÍ£°ì¤Î¥á¥½¥Ã¥É¤Ç¤¹(¥Û¥¹¥È´Ö¤Ç¤Ê¤¯ +_¥æ¡¼¥¶¡¼_ ´Ö¤Î¥Õ¥¡¥¤¥ëžÁ÷¤ò²Äǽ¤Ë¤¹¤ë¡¢¤Á¤ç¤Ã¤ÈÊѤï¤Ã¤¿¥á¥½¥Ã¥É +¤â¤¢¤ê¤Þ¤¹¡£°Ê²¼¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤)¡£ + +¤³¤ì¤é¤Î¥á¥½¥Ã¥É¤ò»È¤¦¤¿¤á¤Ë¤Ï¡¢É乿²½¡¢Éü¹æ²½¤Î¤¿¤á¤Î¥³¥Þ¥ó¥É¤¬¥ê¥â¡¼¥È +¥Þ¥·¥ó¾å¤Ë¸ºß¤·¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£¥í¡¼¥«¥ë¥Þ¥·¥ó¾å¤Ç¤Ï¡¢TRAMP ¤Ï +¥Õ¥¡¥¤¥ë¤òÉü¹æ²½¡¢É乿²½¤¹¤ë Emacs ¤Îµ¡Ç½¤ò»È¤¦¤«¡¢³°Éô¥³¥Þ¥ó¥É¤ò»ÈÍÑ +¤·¤Þ¤¹¡£ + + TRAMP ¤Ï¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¤ª¤¤¤Æ `mimencode' (`metamail' +¥Ñ¥Ã¥±¡¼¥¸¤Î°ìÉô) ¤ä `uuencode' ¤È¤¤¤Ã¤¿ +¥³¥Þ¥ó¥É¤Î¸ºß¤È¡¢¤½¤ì¤¬»È¤¨¤ë¤«¤É¤¦¤«¤òÄ´¤Ù¤Þ¤¹¡£ºÇ½é¤Î¿®Íê¤Ç¤­¤ë¥³¥Þ¥ó¥É¤¬ +»È¤ï¤ì¤Þ¤¹¡£¸¡º÷¥Ñ¥¹¤ò¥«¥¹¥¿¥Þ¥¤¥º¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£*Note Remote +Programs:: ¤ò»²¾È¤·¤Æ²¼¤µ¤¤¡£ + + ¤â¤·¤É¤Á¤é¤Î¥³¥Þ¥ó¥É¤â¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë̵¤«¤Ã¤¿¾ì¹ç¡¢ TRAMP ¤Ï¾®¤µ¤Ê +Perl ¤Î¥³¡¼¥É¤ò¥ê¥â¡¼¥È¥Û¥¹¥È¤ËžÁ÷¤·¡¢¤½¤ì¤ò¥¨¥ó¥³¡¼¥É¤ä¥Ç¥³¡¼¥É¤ËÍѤ¤ +¤è¤¦¤È¤·¤Þ¤¹¡£ + +`rsh' + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë `rsh' ¤ÇÀܳ¤·¤Þ¤¹¡£¥»¥­¥å¥¢¤Ç¤Ê¤¤Àܳ¤Î°Ù¡¢ + ¶Ë¤á¤Æ¥í¡¼¥«¥ë¤Ê¥Û¥¹¥È¥È¥Ý¥í¥¸¡¼°Ê³°¤ËÍѤ¤¤ë¤Ù¤­¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£ + + `rsh' ¤ÎÂå¤ï¤ê¤Ë `remsh' ¥³¥Þ¥ó¥É¤òÄ󶡤¹¤ë¥ª¥Ú¥ì¡¼¥Æ + ¥£¥ó¥°¥·¥¹¥Æ¥à¤Ç¤Ï¥á¥½¥Ã¥É `remsh' ¤ò»È¤¦¤³¤È¤â¤Ç¤­¤Þ¤¹¡£Î㤨¤Ð + HP-UX ¤ä Cray UNICOS ¤Î¾ì¹ç¤¬¤¢¤Æ¤Ï¤Þ¤ê¤Þ¤¹¡£ + +`ssh' + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë `ssh' ¤ÇÀܳ¤·¤Þ¤¹¡£`ssh' ¥Ñ¥Ã¥±¡¼¥¸ + ¤òÍѤ¤¤ÆÀܳ¤ò¤è¤ê¥»¥­¥å¥¢¤Ë¤·¤Æ¤¤¤ë¤³¤È¤ò½ü¤±¤ÐÀè¤Û¤É¤Î¥ª¥×¥·¥ç¥ó¤ÈƱ + ¤¸¤Ç¤¹¡£ + + `ssh1' ¤È `ssh2' ¤È¤¤¤¦Æó¤Ä¤ÎÊѼ郎¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ï `ssh -1' ¤È + `ssh -2' ¤ò¸Æ¤Ó½Ð¤·¤Þ¤¹¡£¤³¤Î¤è¤¦¤Ë¤·¤Æ¡¢ SSH ¥×¥í¥È¥³¥ë¥Ð¡¼¥¸¥ç¥ó + 1 ¤È 2 ¤Î¤É¤Á¤é¤òÍѤ¤¤Æ¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ + ¤¹¤ë¤«¤òÌÀ¼¨Åª¤ËÁªÂò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£(SSH ¤ÎÀßÄê¥Õ¥¡¥¤¥ë + `~/.ssh/config' ¤Ç¤É¤Á¤é¤Î¥×¥í¥È¥³¥ë¤òÍѤ¤¤ë¤«»ØÄꤷ¡¢Ä̾ï¤Î `ssh' + ¥á¥½¥Ã¥É¤òÍѤ¤¤ë ¤³¤È¤â¤Ç¤­¤Þ¤¹¡£) + + ¤Þ¤¿¤½¤Î¤Û¤«¤Ë¡¢ `ssh1_old' ¤È `ssh2_old' ¤È¤¤¤¦Æó¤Ä¤ÎÊѼ郎 + ¸ºß¤·¡¢ÌÀ¼¨Åª¤Ë `ssh1' ¥³¥Þ¥ó¥É¤È `ssh2' ¥³¥Þ¥ó¥É¤ò»È¤¤¤Þ¤¹¡£ + ¤½¤ì¤é¤¬²¿¤«ÃΤé¤Ê¤¤¤Ê¤é¡¢¤³¤ì¤é¤Î¥ª¥×¥·¥ç¥ó¤Ï¤¢¤Ê¤¿¤Ë¤ÏɬÍפ¢¤ê¤Þ¤»¤ó¡£ + + `ssh' ¤Ë´ð¤Å¤¯Á´¤Æ¤Î¥á¥½¥Ã¥É¤Ï¡¢¥¯¥ë¡¼¥¸ÅªÆÃħ¤ò»ý¤Á¤Þ¤¹: + `host#42' + ¤Î¤è¤¦¤Ë¤·¤Æ(¼Â¥Û¥¹¥È̾¤Ë³¤±¤Æ¥Ï¥Ã¥·¥åµ­¹æ¡¢¤½¤·¤Æ¥Ý¡¼¥ÈÈÖ¹æ) + ¥Û¥¹¥È̾¤ò»ØÄꤹ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤³¤ì¤Î°ÕÌ£¤Ï¡¢»ØÄꤷ¤¿¥Û¥¹¥È¤ËÀܳ¤¹¤ëºÝ¤Ë¡¢ + `ssh' ¥³¥Þ¥ó¥É¤Î°ú¿ô¤È¤·¤Æ `-p 42' ¤òÅϤ¹¤È¤¤¤¦¤³¤È¤Ç¤¹¡£ + +`telnet' + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë `telnet' ¤ÇÀܳ¤·¤Þ¤¹¡£¤³¤ì¤Ï `rsh' ¥á¥½¥Ã¥É + ¤ÈƱÍͤ˥»¥­¥å¥¢¤Ç¤Ê¤¤ÊýË¡¤Ç¤¹¡£ + +`su' + ¤³¤Î¥á¥½¥Ã¥É¤Ï¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤·¤Þ¤»¤ó¡£¤½¤Î¤«¤ï¤ê¤Ë `su' + ¥×¥í¥°¥é¥à¤ò»È¤¦¤³¤È¤Ç¾¤Î¥æ¡¼¥¶¤È¤·¤Æ¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë¤³¤È¤ò²Äǽ¤È + ¤·¤Þ¤¹¡£ + +`sudo' + ¤³¤Î¥á¥½¥Ã¥É¤Ï¡¢`su' ¥á¥½¥Ã¥É¤Ë»÷¤Æ¤¤¤Þ¤¹¤¬¡¢°ã¤¦¥æ¡¼¥¶¡¼¤Ë¤Ê¤ë + ¤¿¤á¤Ë `su' ¤Ç¤Ê¤¯ `sudo' ¤ò»ÈÍѤ·¤Þ¤¹¡£ + + ¤½¤Î¥æ¡¼¥¶¡¼¤Ç¥·¥§¥ë¤òµ¯Æ°¤Ç¤­¤ë¤è¤¦¤Ë¡¢`sudo' ¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Ê + ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤³¤È¤ËÃí°Õ¤·¤Æ¤¯¤À¤µ¤¤¡£`ls' ¤È `mimedecode' + ¤Îµ¯Æ°¤Îµö²Ä¤À¤±¤Ç½½Ê¬¤Ç¤¢¤ì¤Ð¤è¤¤¤Î¤Ç¤¹¤¬¡¢¤½¤Î¤è¤¦¤Ë¼ÂÁõ¤¹¤ë¤Î¤Ï´Êñ¤Ç¤Ï + ¤Ê¤¯¡¢¤Þ¤À̵Íý¤Ç¤¹¡£ + +`sshx' + ¤ªÊ¬¤«¤ê¤Î¤è¤¦¤Ë¡¢¤³¤ì¤Ï `ssh' ¤È¤Á¤ç¤Ã¤È°ã¤Ã¤¿Îà»÷ʪ¤Ç¤¹¡£ `ssh' + ¤¬¥ê¥â¡¼¥È¥Û¥¹¥È¤ÇÄ̾ï¤ÎÂÐÏÃŪ¥·¥§¥ë¤ò³«¤¯¤Î¤ËÂФ·¡¢ + ¤³¤Î¥ª¥×¥·¥ç¥ó¤Ï `ssh -t -t HOST -l USER /bin/sh' + ¤ò»È¤Ã¤ÆÀܳ¤ò¹Ô¤Ê¤¤¤Þ¤¹¡£¤³¤ÎÊýË¡¤Ï¡¢Ä̾ï¤Î¥í¥°¥¤¥ó¥·¥§¥ë¤¬¡¢¥í¥°¥¤¥ó + ¤ÎºÝ¤Ë¼ÁÌä¤ò¤·¤Æ¤¯¤ë¤è¤¦¤ËÀßÄꤷ¤Æ¤¢¤ë¾ì¹ç¤ËÍ­ÍѤǤ¹¡£¤³¤Î¼ê½ç¤Ë¤è¤ê + ¤½¤ì¤é¤Î¼ÁÌä¤ò²óÈò¤·¤Æ¡¢`ɸ½àŪ¤Ê' ¥í¥°¥¤¥ó¥·¥§¥ë¤ò TRAMP ¤Ë»È¤ï¤» + ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + ¤³¤Î¼ê³¤­¤Ï `ssh' ¼«¿È¤«¤é¤Î¼ÁÌä¤òÇÓ½ü¤·¤Ê¤¤¤³¤È¤ËÃí°Õ¤·¤Æ²¼ + ¤µ¤¤¡£Î㤨¤Ð¥ê¥â¡¼¥È¥Û¥¹¥È¤Î¥Û¥¹¥È¸°¤¬Ì¤ÃΤÎʪ¤Ç¤¢¤ë¾ì¹ç¤Ë¡¢"Are + you sure you want to continue connecting?" ¤È `ssh' ¤¬¿Ö¤¤¤Æ¤¯¤ë + ¤«¤â¤·¤ì¤Þ¤»¤ó¡£TRAMP ¤Ï(º£¤Î¤È¤³¤í)¤½¤Î¤è¤¦¤Ê¼ÁÌä¤ò°·¤¦ÊýË¡¤òÃΤé + ¤Ê¤¤¤Î¤Ç¡¢¤½¤Î¤è¤¦¤Ê¼ÁÌä¤ò¤µ¤ì¤Ê¤¤¤Ç¥í¥°¥¤¥ó¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Æ¤ª¤¯É¬Íפ¬ + ¤¢¤ê¤Þ¤¹¡£ + + ¤³¤Î¼ê½ç¤Ï¡¢ `ssh' ¤ò Emacs ¥Ð¥Ã¥Õ¥¡¤«¤é¸Æ¤Ö¤È pseudo tty ¤ò³ä + ¤êÅö¤Æ¤Æ¤Ê¤¤¤È¸À¤ï¤ì¤Æ¤·¤Þ¤¦ Windows + ¥æ¡¼¥¶¤Ë¤È¤Ã¤Æ¤âÍ­ÍѤǤ¹¡£¤³¤Î»þ¡¢ + ¥í¥°¥¤¥ó¥·¥§¥ë¤Ï¥·¥§¥ë¥×¥í¥ó¥×¥È¤ò°ìÀÚɽ¼¨¤·¤è¤¦¤È¤·¤Ê¤¯¤Æ¡¢¤½¤ì¤Ï + TRAMP ¤òÂçÊѺ®Í𤵤»¤Æ¤·¤Þ¤¤¤Þ¤¹¡£Ì¤ÃΤÎÍýͳ¤Ë¤è¤ê¡¢¤¤¤¯¤Ä¤«¤Î + `ssh' ¤Î Windows ¤Ø¤Î°Ü¿¢ÈÇ(¤¿¤Ö¤ó Cygwin ¤Î¤â¤Î¤â)¤Ï `-t' + ¥ª¥×¥·¥ç¥ó¤òÆó¤Ä½Å¤Í¤Æ»È¤¦¤³¤È¤òÍ׵ᤷ¤Þ¤¹¡£ + + ¤³¤ì¤Ï `-p' ¥¯¥ë¡¼¥¸¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤¹¡£ + +`krlogin' + ¤³¤Î¥á¥½¥Ã¥É¤â `ssh' ¤Ë»÷¤Æ¤¤¤Þ¤¹¡£¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤¹¤ë¤Î¤Ë + `krlogin -x' ¥³¥Þ¥ó¥É¤ò»È¤¦¤À¤±¤Ç¤¹¡£ + +`plink' + ¤³¤Î¥á¥½¥Ã¥É¤Ï SSH ¤Î PuTTY ¼ÂÁõ¤ò»È¤Ã¤Æ¤¤¤ë Windows ¥æ¡¼¥¶¤Ë¤È¤Ã¤Æ + ¤È¤Æ¤â¶½Ì£¿¼¤¤¤â¤Î¤Ç¤¹¡£¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤¹¤ë¤Î¤Ë `plink + -ssh' ¤ò»È¤¤¤Þ¤¹¡£ + + ¤µ¤é¤Ë¥á¥½¥Ã¥É `plink1' ¤¬Ä󶡤µ¤ì¤Þ¤¹¡£¤½¤ì¤Ï ÌÀ¼¨Åª¤Ë SSH + ¥×¥í¥È¥³¥ë¥Ð¡¼¥¸¥ç¥ó 1 ¤ò»È¤¦¤¿¤á¤Ë `plink -1 -ssh' + ¤ò¸Æ¤Ó½Ð¤·¤Þ¤¹¡£ + + CCC: SSH key + ¤ò¼õÍý¤¹¤ë¤¿¤á¤Ë¥³¥Þ¥ó¥É¥é¥¤¥ó¤«¤é¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø·Ò¤°É¬Í×¤Ï + ¤¢¤ë¤Î¤«? ¤³¤ì¤Ï¼«Æ°²½¤Ç¤­¤Ê¤¤¤«? + + CCC: `plink' ¤Ï `-p' ¥ª¥×¥·¥ç¥ó¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¤«? ¤¤¤º¤ì¤Ë ¤»¤è + TRAMP ¤Ï¤½¤ì¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£ + + + +File: tramp_ja.info, Node: External transfer methods, Next: Multi-hop Methods, Prev: Inline methods, Up: Configuration + +4.3 ³°ÉôžÁ÷¥á¥½¥Ã¥É +==================== + +³°ÉôžÁ÷¥á¥½¥Ã¥É¤ÏÊ£¿ô¤Î¥Á¥ã¥Í¥ë¤ò»ÈÍѤ·¤Þ¤¹¡£¥ª¥Ú¥ì¡¼¥·¥ç¥ó¤Î¤¿¤á¤Ë +¥ê¥â¡¼¥È¥·¥§¥ë¤Î¥³¥Í¥¯¥·¥ç¥ó¤ò»È¤¤¡¢¥Õ¥¡¥¤¥ëžÁ÷¤Ë¤Ï¡¢³°Éô¥×¥í¥°¥é¥à +¤ò»È¤¤¤Þ¤¹¡£ + +¤³¤ì¤Ï¡¢¥¤¥ó¥é¥¤¥óžÁ÷»þ¤Î¡¢¤Ò¤È¤Ä¤Î¥³¥Í¥¯¥·¥ç¥ó¤ò»È¤Ã¤¿Â¿½Å²½Å¾Á÷¤Î¤¿¤á +¤ÎÉ乿²½¡¢Éü¹æ²½¤Î¥ª¡¼¥Ð¡¼¥Ø¥Ã¥É¤òºï¸º¤·¤Þ¤¹¡£ + +³°ÉôžÁ÷¥á¥½¥Ã¥É¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ï¡¢¥Õ¥¡¥¤¥ë¤ò¥³¥Ô¡¼¤¹¤ë¤¿¤á¤ÎžÁ÷¥æ¡¼¥Æ¥£ +¥ê¥Æ¥£¤¬¡¢¥Ñ¥¹¥ï¡¼¥ÉÆþÎϤʤ·¤Ç¼Â¹Ô¤Ç¤­¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£ + + ¤Ä¤Þ¤ê¡¢`scp' ¤ò»È¤¦¾ì¹ç¤ä¡¢»È¤Ã¤Æ¤¤¤ë `scp' ¤¬¥³¥Þ¥ó¥É +¥é¥¤¥ó¤Ç¥Ñ¥¹¥ï¡¼¥É¤ò¼õ¤±ÉÕ¤±¤ë¥Ð¡¼¥¸¥ç¥ó¤Î¾ì¹ç¤Ë¤Ï¡¢`ssh-agent' +¤ò»È¤¦É¬Íפ¬¤¢¤ë¤È¤¤¤¦¤³¤È¤Ç¤¹¡£(1) `ssh' ·Ðͳ¤Ç `rsync' +¤ò»È¤¦¾ì¹ç¤âƱÍͤǤ¹¡£ + + ¤â¤·¡¢¥Ñ¥¹¥ï¡¼¥ÉÆþÎϤʤ·¤Ç `scp' ¤ò¼Â¹Ô¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¤¬¡¢ +¥³¥Í¥¯¥·¥ç¥ó¤ò¥»¥­¥å¥¢¤Ë¤¹¤ë¤¿¤á¤Ë `ssh' ¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ï¡¢ `ssh' +¥Ù¡¼¥¹¤Î¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£ + +`rcp' -- `rsh' ¤È `rcp' + ¤³¤Î¥á¥½¥Ã¥É¤Ï `rsh' ¤È `rcp' ¤ò»È¤¤¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó + ¤ËÀܳ¡¢¥Õ¥¡¥¤¥ëžÁ÷¤ò¤ª¤³¤Ê¤¤¤Þ¤¹¡£¤ª¤½¤é¤¯ºÇ®¤Î¥á¥½¥Ã¥É¤Ç¤¹¡£ + + ¤â¤¦°ì¤ÄÊ̤Υ᥽¥Ã¥É `remcp' ¤Ç¤Ï `remsh' ¥³¥Þ¥ó¥É¤È `rcp' + ¥³¥Þ¥ó¥É¤ò»È¤¤¤Þ¤¹¡£¤³¤ì¤Ï `rsh' ¤ÎÂå¤ï¤ê¤Ë `remsh' + ¤¬»È¤ï¤ì¤ë¥Þ¥·¥ó¾å¤Ç»È¤ï¤ì¤ë¤Ù¤­¤Ç¤¹¡£ + +`scp' -- `ssh' ¤È `scp' + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø¤ÎÀܳ¤Î¤¿¤á¤Î `ssh' ¤ä¡¢¥Þ¥·¥ó´Ö¤Î¥Õ¥¡¥¤¥ëžÁ÷ + ¤Î¤¿¤á¤Î `scp' ¤Ï¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ø¤Î¥»¥­¥å¥¢¤ÊÀܳ¤È¥Õ¥¡¥¤¥ë + ¥¢¥¯¥»¥¹¤Î¤¿¤á¤Ë¤ÏºÇÎɤΥ᥽¥Ã¥É¤Ç¤¹¡£ + + ¤³¤Î¥ª¥×¥·¥ç¥ó¤ÎÀ­Ç½¤âÍ¥¤ì¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¡¢¾®¤µ¤¤¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥×¥ó¡¢ + ¥¯¥í¡¼¥º¤òÉÑÈˤ˷«¤êÊÖ¤¹¾ì¹ç¤Ï¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤è¤êÃÙ¤¯¤Ê¤ê¤Þ¤¹¡£ + `scp'¥»¥Ã¥·¥ç¥ó³«»Ï»þ¤Î°Å¹æ²½¤Î¤¿¤á¤Î¥Ï¥ó¥É¥·¥§¡¼¥¯¤Î¥³¥¹¥È¤Ï¡¢ + É乿²½¡¢Éü¹æ²½¤ò¤ª¤³¤Ê¤ï¤Ê¤¤ÍøÅÀ¤òÄ¢¾Ã¤·¤Ë¤·¤Þ¤¹¡£ + + `scp1' ¤È `scp2' ¤È¤¤¤¦Æó¤Ä¤ÎÊѼ郎¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ï `ssh -1' ¤È + `ssh -2' ¤ò¸Æ¤Ó½Ð¤·¤Þ¤¹¡£¤³¤Î¤è¤¦¤Ë¤·¤Æ¡¢ SSH ¥×¥í¥È¥³¥ë¥Ð¡¼¥¸¥ç¥ó + 1 ¤È 2 ¤Î¤É¤Á¤é¤òÍѤ¤¤Æ¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ + ¤¹¤ë¤«¤òÌÀ¼¨Åª¤ËÁªÂò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£(SSH ¤ÎÀßÄê¥Õ¥¡¥¤¥ë + `~/.ssh/config' ¤Ç¤É¤Á¤é¤Î¥×¥í¥È¥³¥ë¤òÍѤ¤¤ë¤«»ØÄꤷ¡¢Ä̾ï¤Î `scp' + ¥á¥½¥Ã¥É¤òÍѤ¤¤ë ¤³¤È¤â¤Ç¤­¤Þ¤¹¡£) + + ¤Þ¤¿¤½¤Î¤Û¤«¤Ë¡¢ `scp1_old' ¤È `scp2_old' ¤È¤¤¤¦Æó¤Ä¤ÎÊѼ郎 + ¸ºß¤·¡¢ÌÀ¼¨Åª¤Ë `ssh1' ¥³¥Þ¥ó¥É¤È `ssh2' ¥³¥Þ¥ó¥É¤ò»È¤¤¤Þ¤¹¡£ + ¤½¤ì¤é¤¬²¿¤«ÃΤé¤Ê¤¤¤Ê¤é¡¢¤³¤ì¤é¤Î¥ª¥×¥·¥ç¥ó¤Ï¤¢¤Ê¤¿¤Ë¤ÏɬÍפ¢¤ê¤Þ¤»¤ó¡£ + + `ssh' ¤Ë´ð¤Å¤¯Á´¤Æ¤Î¥á¥½¥Ã¥É¤Ï¡¢ `-p' ¤Ë´Ø¤¹¤ë¥¯¥ë¡¼¥¸Åª + ÆÃħ¤ò»ý¤Ã¤Æ¤ª¤ê¡¢¥Û¥¹¥È̾¤ÎÃæ¤Ç¥Ý¡¼¥ÈÈÖ¹æ¤ò»ØÄê¤Ç¤­¤Þ¤¹¡£Î㤨¤Ð¥Û¥¹¥È + ̾¤ò `host#42' ¤È¤¹¤ë¤³¤È¤Ç `ssh' ¥³¥Þ¥ó¥É¤Î°ú¿ô¥ê¥¹¥È¤Ë `-p 42' + ¤ò»ØÄꤹ¤ë¤è¤¦¤Ë TRAMP ¤Ë»Ø¼¨¤Ç¤­¤Þ¤¹¡£ + +`rsync' -- `ssh' ¤È `rsync' + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥»¥­¥å¥¢¤ËÀܳ¤¹¤ë¤¿¤á¤Ë `ssh' ¥³¥Þ¥ó¥É¤ò¡¢ + ¥Õ¥¡¥¤¥ëžÁ÷¤Î¤¿¤á¤Ë `rsync' ¤ò»È¤¦¤Î¤¬¡¢`scp' ¥á¥½¥Ã¥É¤ÎÆÃħ¤Ç¤¹¡£ + + ξ¦¤Î¥Û¥¹¥È¾å¤Ë¸ºß¤¹¤ë¥Õ¥¡¥¤¥ë¤òžÁ÷¤¹¤ë¾ì¹ç¡¢`rsync' ¤Ï `scp' + ¤è¤ê¹âÀ­Ç½¤Ç¤¹¡£¤³¤ÎÍøÅÀ¤Ï¡¢¥Õ¥¡¥¤¥ë¤¬ÊÒ¦¤Î¥Û¥¹¥È¤Ë + ¤·¤«¤Ê¤¤¾ì¹ç¤Ë¤Ï¼º¤Ê¤ï¤ì¤Þ¤¹¡£ + + ¥ê¥â¡¼¥È¥·¥¹¥Æ¥à¤Ø½ñ¤­¹þ¤à¾ì¹ç¡¢`rsync' ¥Ù¡¼¥¹¤Î¥á¥½¥Ã¥É¤Ï `rcp' + ¥Ù¡¼¥¹¤Î¥á¥½¥Ã¥É¤è¤ê¤«¤Ê¤ê®¤¤¤Ç¤·¤ç¤¦¡£¤·¤«¤·¡¢¥í¡¼¥«¥ë + ¥Þ¥·¥ó¤Î¥Õ¥¡¥¤¥ë¤òÆÉ¤ß¹þ¤à¾ì¹ç¤Ï¡¢Ä¾ÀÜ¥³¥Ô¡¼¤¹¤ë¤è¤ê®¤¯¤¢¤ê¤Þ¤»¤ó¡£ + + ¤³¤Î¥á¥½¥Ã¥É¤Ï `-p' ¥Ï¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤¹¡£ + +`scpx' -- `ssh' ¤È `scp' + ÁÛÁüÄ̤ꡢ¤³¤Î¥á¥½¥Ã¥É¤Ï `scp' ¤È¤è¤¯»÷¤Æ¤¤¤Þ¤¹¡£`scp' ¤¬ + ¥ê¥â¡¼¥È¥Û¥¹¥È¾å¤ÇÄ̾ï¤ÎÂÐÏÃŪ¥·¥§¥ë¤òµ¯Æ°¤¹¤ë¤Î¤ËÂФ·¤Æ¡¢¤³¤Î¥ª¥×¥·¥ç¥ó + ¤Ï¥³¥Í¥¯¥·¥ç¥ó¤ò¥ª¡¼¥×¥ó¤¹¤ë¤¿¤á¤Ë `ssh -t -t HOST -l USER /bin/sh' + ¤ò»È¤¤¤Þ¤¹¡£¤³¤Î¥ª¥×¥·¥ç¥ó¤Ï¡¢Ä̾ï¤Î¥í¥°¥¤¥ó¥·¥§¥ë¤¬¥í¥°¥¤¥ó»þ¤Ë¤¤¤¯¤Ä¤« + ¤Î¼ÁÌä¤ò¤ª¤³¤Ê¤¦¤è¤¦¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¤ËÌò¤ËΩ¤Á¤Þ¤¹¡£¤³¤Î¼ê½ç¤Ë¤è¤ê + ¤½¤ì¤é¤Î¼ÁÌä¤ò²óÈò¤·¤Æ¡¢`ɸ½àŪ¤Ê' ¥í¥°¥¤¥ó¥·¥§¥ë¤ò TRAMP ¤Ë»È¤ï¤» + ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + ¤³¤Î¼ê½ç¤Ï Windows ¥æ¡¼¥¶¤Ë¤È¤Ã¤Æ `ssh' ¤ò Emacs ¥Ð¥Ã¥Õ¥¡¤«¤é + ¸Æ¤Ö¤È pseudo tty + ¤ò³ä¤êÅö¤Æ¤Æ¤Ê¤¤¤È¸À¤ï¤ì¤Æ¤·¤Þ¤¦¾ì¹ç¤Ë¤âÍ­ÍѤǤ¹¡£ + ¤³¤Î»þ¥í¥°¥¤¥ó¥·¥§¥ë¤Ï¥·¥§¥ë¥×¥í¥ó¥×¥È¤ò°ìÀÚɽ¼¨¤·¤Ê¤¤¤¿¤á¤Ë TRAMP + ¤ÏÂçÊѺ®Í𤷤Ƥ·¤Þ¤¤¤Þ¤¹¡£¤¿¤Ö¤ó¤³¤ì¤Ï Cygwin ¤Ë°Ü¿¢¤µ¤ì¤¿SSH + ¤Î¾ì¹ç¤Ë Åö¤Æ¤Ï¤Þ¤ê¤Þ¤¹¡£ + + ¤³¤Î¥á¥½¥Ã¥É¤Ï `-p' ¥Ï¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤¹¡£ + +`pscp' -- `plink' ¤È `pscp' + ¤³¤Î¥á¥½¥Ã¥É¤Ï `scp' ¤Ë»÷¤Æ¤¤¤Þ¤¹¤¬¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤¹¤ë¤Î ¤Ë + `plink' ¥³¥Þ¥ó¥É¤ò»È¤¤¡¢¥Õ¥¡¥¤¥ë¤òžÁ÷¤¹¤ë¤Î¤Ë `pscp' + ¤ò»È¤¤¤Þ¤¹¡£¤³¤ì¤é¤Î¥³¥Þ¥ó¥É¤Ï Windows ÍѤΠSSH ¼ÂÁõ¤Ç¤¢¤ë PuTTY ¤Ë + ´Þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£ + + CCC: `plink' ¤Ï `-p' ¥Ï¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¤«? + +`fcp' -- `fsh' ¤È `fcp' + ¤³¤Î¥á¥½¥Ã¥É¤Ï `scp' ¤Ë»÷¤Æ¤¤¤Þ¤¹¤¬¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤¹¤ë¤Î ¤Ë + `fsh' ¥³¥Þ¥ó¥É¤ò»È¤¤¡¢¥Õ¥¡¥¤¥ë¤òžÁ÷¤¹¤ë¤Î¤Ë `fcp' ¤ò»È¤¤¤Þ¤¹¡£ + `fsh/fcp' ¤Ï `ssh' ¤Î¥Õ¥í¥ó¥È¥¨¥ó¥É¤Ç¡¢ Ʊ°ì¤Î `ssh' + ¥»¥Ã¥·¥ç¥ó¤òºÆÍøÍѤ·¤Æ¤¤¤¯¤Ä¤«¤Î¥³¥Þ¥ó¥É¤òÁ÷¤ë¤³ + ¤È¤ò²Äǽ¤È¤·¤Þ¤¹¡£¤³¤ì¤Ë¤è¤ê¡¢`scp' ¤Îµ¯Æ°¤Ë¤«¤«¤ë¥ª¡¼¥Ð¡¼¥Ø¥Ã¥É + (¸Æ¤Ð¤ì¤ëÅ٤˥»¥­¥å¥¢¤ÊÀܳ¤ò³ÎΩ¤·¤Ê¤¤¤È¤¤¤±¤Ê¤¤)¤ò²óÈò¤Ç¤­¤Þ¤¹¡£ + °ìÊý¡¢Æ±Íͤθú²Ì¤òÆÀ¤ë¤¿¤á¤Ë¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤Î¤É¤ì¤«¤òÍѤ¤¤ë¤³¤È¤â + ¤Ç¤­¤ë¤³¤È¤òÃí°Õ¤·¤Æ¤ª¤­¤Þ¤¹¡£ + + ¤³¤Î¥á¥½¥Ã¥É¤Ï¥³¥Þ¥ó¥É `fsh HOST -l USER /bin/sh -i' + ¤ò»È¤Ã¤ÆÀܳ¤ò³ÎΩ¤·¤Þ¤¹¡£Ã±¤Ë `fsh HOST -l USER' + ¤È¤·¤¿¤À¤±¤Ç¤Ïư¤­¤Þ¤»¤ó¡£ + + `fsh' ¥×¥í¥°¥é¥à¤¬Ä󶡤¹¤ë¿½Å²½¤Ï²æ¡¹¤Îʸ̮¤Ç¤Ï¤½¤ì¤Û¤ÉÍ­ÍÑ¤Ç + ¤Ï¤Ê¤¤¤Î¤Ç¡¢¤½¤ì¤òÍѤ¤¤ë¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤Ï¸ºß¤·¤Þ¤»¤ó¡£¤½¤ÎÂå¤ï¤ê + TRAMP + ¤Ïñ¤Ë¥ê¥â¡¼¥È¥Û¥¹¥È¤Ø¤Î°ì¤Ä¤ÎÀܳ¤ò³«¤­¡¢¤½¤ÎÀܳ¤òÊÝ»ý¤·¤Þ¤¹¡£ + +`smb' -- `smbclient' + ¤³¤ì¤Ï¤Þ¤¿Ê̤ΠTRAMP ÆÈ¼«¤Ç¤Ê¤¤¥á¥½¥Ã¥É¤Ç¤¹¡£`smbclient' + ¥³¥Þ¥ó¥É¤òÊ̤ΠUnices ¾å¤Ç»È¤Ã¤Æ¡¢SMB ¥µ¡¼¥Ð¤Ø¤ÎÀܳ¤ò¹Ô¤Ê¤¤¤Þ¤¹¡£ + SMB ¥µ¡¼¥Ð¤ÏÊ̤ΠUNIX ¥Û¥¹¥È¾å¤Î Samba (¤â¤·¤¯¤Ï CIFS) + ¥µ¡¼¥Ð¤Ç¤¢¤ë¤« ¤â¤·¤ì¤Þ¤»¤ó¤·¡¢¤µ¤é¤Ë¶½Ì£¿¼¤¤¤³¤È¤Ë¡¢MS Windows + ¤¬Æ°¤¤¤Æ¤¤¤ë¥Û¥¹¥È¤Ç ¤¢¤ë¤«¤â¤·¤ì¤Ê¤¤¤Î¤Ç¤¹¡£º£¤Î¤È¤³¤í¡¢MS + Windows NT¡¢MS Windows 2000¡¢ ¤ª¤è¤Ó MS Windows XP + ¤ËÂФ·¤Æ¥Æ¥¹¥È¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ + + ¥í¡¼¥«¥ë̾¤ÎÀèÆ¬¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ï¥ê¥â¡¼¥È¥Û¥¹¥È¤Ç¤Î¶¦Í­Ì¾¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê + ¤Þ¤»¤ó¡£Ä̾ï¥Ç¥Õ¥©¥ë¥È¤Î¶¦Í­¤Î½ªÃ¼¤Ïʸ»ú `$' ¤Ç¤¹¤¬¡¢¥Õ¥¡¥¤¥ë̾¤Î + ´Ä¶­ÊÑ¿ô¤Ë¤è¤ëŸ³«¤Î¤¿¤á¡¢¤½¤ì¤ò `$$' ¤È½ñ¤¯É¬Íפ¬¤¢¤ë¤³¤È¤ò²±¤¨¤Æ + ¤ª¤¤¤Æ²¼¤µ¤¤¡£¤â¤·¡¢¶¦Í­Ì¾¤¬Í¿¤¨¤é¤ì¤Ê¤±¤ì¤Ð(¤¹¤Ê¤ï¤Á¥ê¥â¡¼¥È¥Ç¥£¥ì¥¯¥È¥ê + ¤¬ `/' ¤Î¾ì¹ç)¡¢Á´¤Æ¤ÎÍøÍѲÄǽ¤Ê¶¦Í­¤¿¤Á¤¬É½¼¨¤µ¤ì¤Þ¤¹¡£ + + ǧ²Ä¤Ï¶¦Í­¥ì¥Ù¥ë¤Ç¤Ê¤µ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢Æ±¤¸¥Û¥¹¥È¤Ç¤¢¤Ã¤Æ¤âÊ̤ζ¦Í­¤Ë¥¢¥¯ + ¥»¥¹¤¹¤ë¤Èɬ¤º¥Ñ¥¹¥ï¡¼¥É¤òµá¤á¤é¤ì¤Þ¤¹¡£¥»¥­¥å¥ê¥Æ¥£¾å¤ÎÍýͳ¤«¤é¥Ñ¥¹¥ï + ¡¼¥É¤Ï¥­¥ã¥Ã¥·¥å¤µ¤ì¤Þ¤»¤ó¡£ + + MS Windows + ¤Ïǧ²Ä¤Î¤¿¤á¤Ë¥æ¡¼¥¶Ì¾¤È¥É¥á¥¤¥ó̾¤ÎξÊý¤òÍѤ¤¤Þ¤¹¡£¤³¤Î¤¿ + ¤á¡¢TRAMP ¹½Ê¸¤Ï³ÈÄ¥¤µ¤ì¤Þ¤·¤¿: ¥æ¡¼¥¶Ì¾¤ò»ØÄꤹ¤ëºÝ¤Ë + `user%domain' + (¼Â¥æ¡¼¥¶Ì¾¡¢¥Ñ¡¼¥»¥ó¥Èµ­¹æ¡¢¥É¥á¥¤¥ó̾)¤Î¤è¤¦¤Ë½ñ¤¯¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + ¤·¤¿¤¬¤Ã¤Æ¡¢¥Þ¥·¥ó `melancholia' ¤Ë¥É¥á¥¤¥ó `BIZARRE' ¤Î¥æ¡¼¥¶ + `daniel' ¤È¤·¤ÆÀܳ¤·¤Æ¡¢¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê (¶¦Í­ `daniel$') + ¤Ë¤¢¤ë `.emacs' ¤òÊÔ½¸¤¹¤ë¾ì¹ç¡¢¥Õ¥¡¥¤¥ë̾¤ò + `/[smb/daniel%BIZARRE@melancholia]/daniel$$/.emacs' ¤È»ØÄꤷ¤Þ¤¹¡£ + + ¥É¥á¥¤¥ó̾¤ä¥æ¡¼¥¶Ì¾¤ÏÉÕ¤±¤Ê¤¤¤³¤È¤â¤Ç¤­¤Þ¤¹¡£¤â¤·¥æ¡¼¥¶Ì¾¤¬»ØÄꤵ¤ì¤Ê + ¤±¤ì¤Ðƿ̾¥æ¡¼¥¶(¥Ñ¥¹¥ï¡¼¥ÉÆþÎϤÎɬÍפ¬¤Ê¤¤)¤¬²¾Äꤵ¤ì¤Þ¤¹¡£¤³¤ì¤Ï¾¤Î + Á´¤Æ¤Î TRAMP ¥á¥½¥Ã¥É¤È°Û¤Ê¤ê¤Þ¤¹¡£Â¾¤Î¥á¥½¥Ã¥É¤ÇƱ¤¸¾õ¶·¤Î¾ì¹ç¤Ë¤Ï + ¥í¡¼¥«¥ë¥æ¡¼¥¶Ì¾¤¬»È¤ï¤ì¤Þ¤¹¡£ + + `smb' ¥á¥½¥Ã¥É¤Ï `-p' ¥Ï¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤¹¡£ + + *Ãí°Õ¤·¤Æ²¼¤µ¤¤:* ¤â¤· Emacs ¤¬¥í¡¼¥«¥ë¤Î MS Windows ¤Î²¼¤Çư¤¤ + ¤Æ¤¤¤ë¤Ê¤é¤Ð¤³¤Î¥á¥½¥Ã¥É¤ÏÍøÍѤǤ­¤Þ¤»¤ó¡£¤½¤ÎÂå¤ï¤ê¤Ë¡¢ + `//melancholia/daniel$$/.emacs' ¤Î¤è¤¦¤Ê UNC ¥Õ¥¡¥¤¥ë̾¤ò»È¤¦¤³¤È + ¤¬¤Ç¤­¤Þ¤¹¡£Í£°ì¤Î·çÅÀ¤Ï¾¤Î¥æ¡¼¥¶Ì¾¤ò»ØÄꤹ¤ë¤¿¤á¤ÎÊýË¡¤¬Ìµ¤¤¤³¤È¤Ç¤¹¡£ + + + ---------- Footnotes ---------- + + (1) PuTTY's `pscp' ¤Ç¤Ï ¥³¥Þ¥ó¥É¥é¥¤¥ó¤Ç¥Ñ¥¹¥ï¡¼¥É¤ò»ØÄê¤Ç¤­¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Multi-hop Methods, Next: Default Method, Prev: External transfer methods, Up: Configuration + +4.4 Ê£¿ô¤Î¥Û¥Ã¥×¤ò»È¤¤¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤¹¤ë +============================================== + +¤³¤ì¤Þ¤Ç¤ËÀâÌÀ¤·¤¿¥á¥½¥Ã¥É¤Ç¤ÏÉÔ½½Ê¬¤Ê»ö¤¬¤¢¤ê¤Þ¤¹¡£¥·¥ó¥×¥ë¤Ê¥á¥½¥Ã¥É¤ò +»È¤Ã¤Æ¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤Ç¤­¤Ê¤¤¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£¤¿¤È¤¨¤Ð¡¢¥»¥­¥å¥¢¤Ê +¥Í¥Ã¥È¥ï¡¼¥¯¤ÎÃæ¤Ë¤¤¤ë¾ì¹ç¡¢³°Éô¤ËÀܳ¤¹¤ëÁ°¤Ë¤Þ¤ºÍ׺ɥۥ¹¥È¤Ë¥í¥°¥¤¥ó +¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤Ç¤·¤ç¤¦¡£¤â¤Á¤í¤ó¡¢¥¿¡¼¥²¥Ã¥È¥Û¥¹¥È¤ÏÍ׺ɥۥ¹¥È¤âÍ×µá +¤·¤Þ¤¹¡£¥Þ¥ë¥Á¥Û¥Ã¥×¤Î¥Õ¥¡¥¤¥ë̾¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤Ï¡¢Ä̾ï¤Î TRAMP ¤Î +¥á¥½¥Ã¥É¤È¤¹¤³¤·°Û¤Ê¤ê¤Þ¤¹¡£ + + ¥Þ¥ë¥Á¥Û¥Ã¥×¤Î¥Õ¥¡¥¤¥ë̾¤Ï¡¢¥á¥½¥Ã¥É̾¡¢¥Û¥Ã¥×¿ô¡¢¥í¡¼¥«¥ë̾(¥ê¥â¡¼¥È +¥·¥¹¥Æ¥à¾å¤Î¥Ñ¥¹Ì¾)¤ò»ØÄꤷ¤Þ¤¹¡£¥á¥½¥Ã¥É̾¤Ï¾ï¤Ë `multi' ¤Ç¤¹¡£ + + ³Æ¥Û¥Ã¥×¤Ï "¥Û¥Ã¥×¥á¥½¥Ã¥É" »ØÄê¡¢¤Ä¤Þ¤ê¥æ¡¼¥¶Ì¾¤È¥Û¥¹¥È̾¤«¤éÀ®¤ê +¤Þ¤¹¡£¥Û¥Ã¥×¥á¥½¥Ã¥É¤Ï¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤Î¤ß¤Ë¤Ê¤êÆÀ¤Þ¤¹¡£°Ê²¼¤Î¥Û¥Ã¥× +¥á¥½¥Ã¥É¤¬(º£¤Î¤È¤³¤í)ÍøÍѲÄǽ¤Ç¤¹: + +`telnet' + ¥Û¥¹¥È¤Ø¤ÎÀܳ¤Ë¤è¤¯ÃΤé¤ì¤¿ `telnet' ¥×¥í¥°¥é¥à¤ò»ÈÍѤ·¤Þ¤¹¡£ + ¥æ¡¼¥¶¡¼Ì¾¤È¥Û¥¹¥È̾¤Ï¥Õ¥¡¥¤¥ë̾¤ÎÃæ¤Ë´Þ¤Þ¤ì¡¢¥Ñ¥¹¥ï¡¼¥É¤ò¤¿¤º¤Í¤é¤ì¤Þ¤¹¡£ + +`rsh' + ¥Û¥¹¥È¤Ø¤ÎÀܳ¤Ë `rsh' ¤ò»ÈÍѤ·¤Þ¤¹¡£`rsh' ¤¬¥Ñ¥¹¥ï¡¼¥É + ¤ò¤¿¤º¤Í¤ë»þ°Ê³°¤Ï¡¢¥Ñ¥¹¥ï¡¼¥É¤òÆþÎϤ¹¤ëɬÍפϤ¢¤ê¤Þ¤»¤ó¡£ + + ¤³¤ÎÊѼï `remsh' ¤Ï `remsh' ¥³¥Þ¥ó¥É¤ò»È¤¤¤Þ¤¹¡£¤³¤ì¤Ï `rsh' + ¤ÎÂå¤ï¤ê¤Ë `remsh' ¤¬»È¤ï¤ì¤ë¥Þ¥·¥ó¾å¤Ç»È¤ï¤ì¤ë ¤Ù¤­¤Ç¤¹¡£ + +`ssh' + ¤³¤Î¥á¥½¥Ã¥É¤Ï¥Û¥¹¥È¤Ø¤ÎÀܳ¤Î¤¿¤á¤Ë `ssh' ¤ò»ÈÍѤ·¤Þ¤¹¡£¥Ñ¥¹¥ï¡¼¥É + ¤«¥Ñ¥¹¥Õ¥ì¡¼¥º¤òÆþÎϤ¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£ + +`su' + ¤³¤Î¥á¥½¥Ã¥É¤Ï¾¤Î¥Û¥¹¥È¤Ø¤Þ¤Ã¤¿¤¯¥¢¥¯¥»¥¹¤·¤Þ¤»¤ó¡£¤½¤Î¤«¤ï¤ê¡¢º£¤¤¤ë + ¥Û¥¹¥È¾å¤Ç¾¤Î¥æ¡¼¥¶¡¼¤Ë¤Ê¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤³¤ì¤Ï¡¢root + ¤È¤·¤Æ¥Õ¥¡¥¤¥ë ¤òÊÔ½¸¤·¤¿¤¤¤¬¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¤Ï¥ê¥â¡¼¥È¤«¤é¤Î root + ¤Î¥í¥°¥¤¥ó¤òµö²Ä¤·¤Æ + ¤¤¤Ê¤¤¾ì¹ç¤ËÌò¤ËΩ¤Á¤Þ¤¹¡£¤³¤Î¤è¤¦¤Ê¾ì¹ç¡¢°ìÈ̥桼¥¶¡¼¤Ç¤Î¥ê¥â¡¼¥È¥Û¥¹¥È + ¤Ø¤ÎÀܳ¤Ë `telnet'¡¢`rsh' ¤¢¤ë¤¤¤Ï `ssh' ¤ò»È¤¦ + ¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤½¤ì¤«¤é¡¢root ¤Ë¤Ê¤ë¤¿¤á¤Ë `su' ¥Û¥Ã¥×¤ò»È¤¤¤Þ¤¹¡£ + `su' ¤Ï°ìÏ¢¤Î¥·¡¼¥¯¥¨¥ó¥¹Ãæ¤ÎºÇ¸å¤Î¥Û¥Ã¥×¤Ç¤¢¤ëɬÍפϤ¢¤ê¤Þ¤»¤ó¡£ + ɬÍפǤ¢¤ì¤Ð¥Û¥Ã¥×Ãæ¤Î¤É¤³¤Ç¤Ç¤â»È¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + `su' ¥Û¥Ã¥×¤È°ì½ï¤Ë¥æ¡¼¥¶¡¼¤È¥Û¥¹¥ÈξÊý¤ò»ØÄꤷ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£ + ¤·¤«¤·¤Ê¤¬¤é¡¢¥Û¥¹¥È̾¤Ï̵»ë¤µ¤ì¥æ¡¼¥¶¡¼Ì¾¤À¤±¤¬»ÈÍѤµ¤ì¤Þ¤¹¡£ + +`sudo' + ¤³¤ì¤Ï `su' ¥Û¥Ã¥×¤Ë»÷¤Æ¤¤¤Þ¤¹¡£°ã¤¦¥æ¡¼¥¶¡¼¤Ë¤Ê¤ë¤¿¤á¤Ë `su' + ¤Ç¤Ê¤¯ `sudo' ¤ò»ÈÍѤ¹¤ëÅÀ¤¬°Û¤Ê¤ê¤Þ¤¹¡£ + + + `ssh' ¤òÍѤ¤¤Æ¥Ý¡¼¥È¥Õ¥©¥ï¡¼¥É¤ò¤·¤¿¤¤¾ì¹ç¤ä¡¢É¸½àŪ¤Ç¤Ê¤¤¥Ý¡¼¥È¤ò +»ÈÍѤ·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¾ì¹ç¤¬¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤½¤Î¤è¤¦¤Ê¾ì¹ç¤Ë¤Ï¡¢ +¥Û¥¹¥È̾¤´¤È¤Ë°Û¤Ê¤ë¥Ý¡¼¥ÈÈÖ¹æ¤ò»ØÄꤷ¤¿µ­½Ò¤ò `~/.ssh/config' ¤Ë +½ñ¤­¹þ¤à¤³¤È¤Ç¼Â¸½¤Ç¤­¤Þ¤¹¡£¤·¤«¤·¤Ê¤¬¤é¡¢¥Þ¥ë¥Á¥Û¥Ã¥×¥á¥½¥Ã¥É¤ò»È¤¨¤Ð +¤½¤ì¤Ï TRAMP ¤ÎÏÈÆâ¤Ç¼Â¸½¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£Î㤨¤Ð: + + (add-to-list + 'tramp-multi-connection-function-alist + '("sshf" tramp-multi-connect-rlogin "ssh %h -l %u -p 4400%n")) + + ¤È¤¹¤ì¤Ð¡¢ `sshf' ¥Û¥Ã¥×¤òÍѤ¤¤Æ¡¢É¸½àŪ¤Ê¥Ý¡¼¥È¤ÎÊѤï¤ê¤Ë 4400 ÈÖ +¥Ý¡¼¥È¤Ø·Ò¤°¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Default Method, Next: Customizing Methods, Prev: Multi-hop Methods, Up: Configuration + +4.5 ¥Ç¥Õ¥©¥ë¥È¤Î¥á¥½¥Ã¥É¤ÎÁªÂò +============================== + +ÉáÃʤ褯»È¤¦Å¬ÀڤʞÁ÷¥á¥½¥Ã¥É¤òÁªÂò¤¹¤ë¤Ë¤Ï¡¢ÊÑ¿ô +`tramp-default-method' ¤òÀßÄꤷ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£¤³¤ÎÊÑ¿ô¤Ë¤Ï TRAMP +¥Õ¥¡¥¤¥ë̾¤Ë¥á¥½¥Ã¥É¤¬ +»ØÄꤵ¤ì¤Ê¤«¤Ã¤¿»þ¤Ë»ÈÍѤµ¤ì¤ë¥Ç¥Õ¥©¥ë¥È¤Î¥á¥½¥Ã¥É¤òÀßÄꤷ¤Þ¤¹¡£ Î㤨¤Ð: + + (setq tramp-default-method "scp") + + ÊÑ¿ô `tramp-default-method-alist' ¤ò»È¤Ã¤ÆÆÃÄê¤Î¥æ¡¼¥¶/¥Û¥¹¥È¤Î +ÁȤ߹ç¤ï¤»¤ËÂФ·¤Æ°Û¤Ê¤Ã¤¿¥á¥½¥Ã¥É¤ò»ØÄꤹ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£Î㤨¤Ð +¼¡¤Î2¹Ô¤Ï¡¢¥æ¡¼¥¶Ì¾¤¬ `john' ¤Ë¥Þ¥Ã¥Á¤¹¤ë¾ì¹ç¤Ë¤Ï `ssh' +¥á¥½¥Ã¥É¤òÍѤ¤¡¢¥Û¥¹¥È̾¤¬ `lily' ¤Ë¥Þ¥Ã¥Á¤¹¤ë¾ì¹ç¤Ë¤Ï `rsync' +¥á¥½¥Ã¥É¤òÍѤ¤¤Þ¤¹¡£3¹ÔÌܤϥޥ·¥ó `localhost' ¾å¤Î¥æ¡¼¥¶`root' ¤ËÂФ·¤Æ +`su' ¥á¥½¥Ã¥É¤ò»È¤¦¤è¤¦¤Ë»ØÄꤷ¤Þ¤¹¡£ + + (add-to-list 'tramp-default-method-alist '("" "john" "ssh")) + (add-to-list 'tramp-default-method-alist '("lily" "" "rsync")) + (add-to-list 'tramp-default-method-alist + '("\\`localhost\\'" "\\`root\\'" "su")) + +¤µ¤é¤Ê¤ë¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤ÏÊÑ¿ô `tramp-default-method-alist' ¤Î¥É¥­¥å¥á¥ó¥È +¤ò¸«¤Æ²¼¤µ¤¤¡£ + +°ìÈÌŪ¤Ë¤Ï¡¢¥¤¥ó¥é¥¤¥óžÁ÷¥á¥½¥Ã¥É¤è¤ê¤Ï³°ÉôžÁ÷¥á¥½¥Ã¥É¤òÁª¤Ö¤Ù¤­¤Ç¤¹¡£ +³°ÉôžÁ÷¥á¥½¥Ã¥É¤Ï¥¤¥ó¥é¥¤¥ó¤è¤ê¹âÀ­Ç½¤Ç¤¹¡£¤·¤«¤·¡¢³°ÉôžÁ÷¥á¥½¥Ã¥É¤Ï¡¢ +¥Ñ¥¹¥ï¡¼¥ÉÆþÎϤʤ·¤Ç¥í¥°¥¤¥ó¤Ç¤­¤Ê¤¤¥ê¥â¡¼¥È¥Þ¥·¥ó¤¬¤¿¤¯¤µ¤ó¤¢¤ë¾ì¹ç¤Ï +Ìò¤ËΩ¤Á¤Þ¤»¤ó¡£ + + *Note Inline methods::. *Note External transfer methods::. *Note +Multi-hop Methods::. + + žÁ÷¥á¥½¥Ã¥É¤ÎÁªÂò¤ò¤¹¤ë»þ¤Ë¾¤Ë¹Íθ¤¹¤Ù¤­»ö¤Ï¡¢¤½¤ì¤é¤ò»È¤¦´Ä¶­¤È¡¢ +ÆÃ¤Ë¥¤¥ó¥¿¡¼¥Í¥Ã¥È¾å¤Ç»È¤¦¾ì¹ç¤¢¤Ê¤¿¤ÎÁªÂò¤·¤¿¥á¥½¥Ã¥É¤Î¥»¥­¥å¥ê¥Æ¥£ +¤È¤Î´Ø·¸¤Ç¤¹¡£ + + `rsh' ¤È `telnet' ¥á¥½¥Ã¥É¤Ï¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ë¥í¥°¥¤¥ó +¤¹¤ë»þ¤Ë¡¢¥Ñ¥¹¥ï¡¼¥É¤ò¥×¥ì¥¤¥ó¥Æ¥­¥¹¥È¤ÇÁ÷¿®¤·¤Þ¤¹¡£¥Õ¥¡¥¤¥ëžÁ÷¤âƱ¤¸ +ÊýË¡¤Ç¤ª¤³¤Ê¤¦¤Î¤Ç¡¢Â¾¤â¥Þ¥·¥ó¤«¤é¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤ò´Êñ¤ËÆÉ¤à¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + +¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤«¤é¥¢¥¯¥»¥¹²Äǽ¤Ê¥ê¥â¡¼¥È¥·¥¹¥Æ¥à¤ËÀܳ¤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¡¢ +Àܳ¤Ë `ssh' ¥Ù¡¼¥¹¤Î¥á¥½¥Ã¥É¤ò»ÈÍѤ¹¤ë¤³¤È¤ò¿¿·õ¤Ë¹Í¤¨¤ë¤Ù¤­¤Ç¤¹¡£ +¤³¤Î¥á¥½¥Ã¥É¤Ï¡¢¹â¤¤¥ì¥Ù¥ë¤Î¥»¥­¥å¥ê¥Æ¥£¤òÄ󶡤·¡¢Ã¯¤«¤¬¥Ñ¥¹¥ï¡¼¥É¤òÆþ¼ê +¤·¤¿¤ê¡¢ÊÔ½¸¤·¤Æ¤¤¤ë¥Õ¥¡¥¤¥ë¤ÎÆâÍÆ¤òÆÉ¤ó¤À¤ê¤¹¤ë¤³¤È¤òº¤Æñ¤Ë¤·¤Þ¤¹¡£ + +4.5.1 »ä¤Ï¤É¤Î¥á¥½¥Ã¥É¤ò»È¤¦¤Ù¤­¤«? +----------------------------------- + +¤³¤³¤Þ¤Ç¤ÎÀâÌÀ¤Ç¡¢¤³¤ì¤ÏÁ´¤¯¤¹¤Ð¤é¤·¤¯¤ÆÎɤ¤¤â¤Î¤À¤¬¡¢¤·¤«¤·¤Ê¤¬¤é¥á¥½¥Ã¥É +¤òÁª¤ÖÊýË¡¤Ë¤Ä¤¤¤Æ¤Ï²¿¤Î½õ¸À¤â¤µ¤ì¤Æ¤Ê¤¤¤è! +¤È»×¤¦¤³¤È¤È»×¤¤¤Þ¤¹¡£³Î¤«¤Ë¡£ +³«È¯¼Ô¤È¤·¤Æ¤Ï¡¢¥æ¡¼¥¶¤òµí¼ª¤í¤¦¤È¤Ï»×¤Ã¤Æ¤Ê¤¯¤Æ¡¢Âå¤ï¤ê¤ËºÇÂç¸Â¤Î¼«Í³ÅÙ¤ò +Í¿¤¨¤è¤¦¤È¹Í¤¨¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¤Ê¤¬¤é¼ÂºÝ¤Ë¤Ï¥æ¡¼¥¶¤ÎÃæ¤Ë¤Ï¼ê°ú¤­¤òµá¤á¤ë +¿Í¤âµï¤ë¤Ç¤·¤ç¤¦¡£¤½¤³¤Ç¤³¤³¤Ç¤Ï¤¢¤Ê¤¿¤ò»ÙÇÛ¤¹¤ë¤³¤È¤Ê¤¯¼ê°ú¤­¤òÍ¿¤¨¤ë¤³¤È +¤ò»î¤ß¤Þ¤¹¡£¤³¤ì¤¬¤¦¤Þ¤¯¹Ô¤Ã¤¿¤«¶µ¤¨¤Æ²¼¤µ¤¤¤Í ... + +»ä¤ÎÄó°Æ¤Ï¡¢¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤ò»È¤¦¤³¤È¤Ç¤¹¡£Â礭¤Ê¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ¤Ï +out-of-band ¥á¥½¥Ã¥É¤ÎÊý¤¬Í­¸ú¤«¤â¤·¤ì¤Þ¤»¤ó¤¬¡¢¤Û¤È¤ó¤É¤Î¿Í¤Ï¾®¤µ¤Ê +¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤¿¤¤¤È»×¤¦¤È¿ä¬¤·¤Þ¤¹¡£ + + º£Æü¤Ç¤Ï¡¢¤Û¤È¤ó¤É¤Î¿Í¤¬¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ë `ssh' ¤ò»È¤Ã¤Æ¥¢¥¯¥»¥¹ +¤Ç¤­¤ë¤È¿ä¬¤·¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ `ssh' ¥á¥½¥Ã¥É¤ò»È¤¦¤³¤È¤òÄ󰯤·¤Þ¤¹¡£ +¤Ä¤Þ¤ê¡¢Â¾¤Î¥Û¥¹¥È¤Î `/etc/motd' ¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë¤¿¤á¤Ë¤Ï `C-x C-f +/ssh:root@otherhost:/etc/motd ' ¤ÈÆþÎϤ¹¤ì¤Ð¤è¤¤ ¤Ç¤¹¡£ + + ¤â¤·¡¢`ssh' ¤ò»È¤Ã¤Æ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤Ç¤­¤Ê¤¤¤Ê¤é¡¢Æ°ºî¤¹¤ë +¥×¥í¥°¥é¥à¤ò»È¤¦¥á¥½¥Ã¥É¤òÁªÂò¤·¤Þ¤¹¡£Î㤨¤Ð Windows ¥æ¡¼¥¶¤Ï `ssh' ¤Î +PuTTY ¼ÂÁõ¤ò»È¤¦ `plink' ¥á¥½¥Ã¥É¤ò¹¥¤à¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤Þ¤¿¡¢ Kerberos +¤ò»È¤Ã¤Æ¤¤¤ë¤Ê¤é `krlogin' ¤ò¹¥¤à¤Ç¤·¤ç¤¦¡£ + +ÆÃÊ̤ʾì¹ç¤È¤·¤Æ¥í¡¼¥«¥ë¥Û¥¹¥È¤Î¥Õ¥¡¥¤¥ë¤òÊ̤Υ桼¥¶¤È¤·¤ÆÊÔ½¸¤·¤¿¤¤¾ì¹ç +¤Ë¤Ï `su' ¥á¥½¥Ã¥É¤â¤·¤¯¤Ï `sudo' ¥á¥½¥Ã¥É¤ò»²¾È¤·¤Æ²¼¤µ¤¤¡£ + + Â礭¤Ê¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë¿Í¤Ï `ssh' ¤ÎÂå¤ï¤ê¤Ë `scp' ¡¢¤â¤·¤¯¤Ï +`plink' ¤ÎÂå¤ï¤ê¤Ë `pscp' ¤ÎÍøÍѤò¹Í¤¨¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£ ¤³¤ì¤é¤Î +out-of-band ¥á¥½¥Ã¥É¤ÏÂ礭¤Ê¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ¤Ï¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É +¤è¤ê¤â¹â®¤Ç¤¹¡£¤·¤«¤·¡¢out-of-band ¥á¥½¥Ã¥É¤¿¤Á¤Ï¤¤¤¯¤Ä¤«¤ÎÀ©¸Â +¤ò¼õ¤±¤ë¤«¤â¤·¤ì¤Ê¤¤¤³¤È¤ËÃí°Õ¤·¤Æ²¼¤µ¤¤¡£ºÇ½é¤ËËÜÅö¤Ë¸²Ãø¤Ê®ÅÙŪ¤Ê +Í¥°Ì¤ò out-of-band +¥á¥½¥Ã¥É¤ÇÆÀ¤é¤ì¤ë¤«»î¤·¤Æ²¼¤µ¤¤!¤ª¤½¤é¤¯Â礭¤Ê¥Õ¥¡¥¤¥ë +¤ËÂФ·¤Æ¤â¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤¿¤Á¤Ï½½Ê¬¹â®¤À¤È»×¤¤¤Þ¤¹¡£ + + »ä¤¬¥¤¥ó¥é¥¤¥ó¥á¥½¥Ã¥É¤ÎÍøÍѤòÄ󰯤¹¤ëÍýͳ¤Ï¡¢¤½¤ì¤é¤Ï¥ê¥â¡¼¥È¦¤¬ +¥Ñ¥¹¥ï¡¼¥É¤òʹ¤¤¤Æ¤­¤¿¤È¤·¤Æ¤âưºî¤¹¤ë¤«¤é¤Ç¤¹¡£out-of-band ¥á¥½¥Ã¥É +¤Ï¤½¤Î¤è¤¦¤Ê¾õ¶·¤Ç¤Ïưºî¤·¤Þ¤»¤ó¡£¤Þ¤¿¡¢¥Þ¥ë¥Á¥Û¥Ã¥×¥á¥½¥Ã¥É¤¿¤Á¤Ï +ËܼÁŪ¤Ë¥¤¥ó¥é¥¤¥ó¤Ç¤¹¡£ + + +File: tramp_ja.info, Node: Customizing Methods, Next: Customizing Completion, Prev: Default Method, Up: Configuration + +4.6 Èóɸ½à¤Î¥á¥½¥Ã¥É¤ò»È¤¦ +========================== + +»öÁ°¤ËÄêµÁ¤µ¤ì¤¿¥á¥½¥Ã¥É¤À¤±¤Ç¤ÏÉÔ½½Ê¬¤Ê¾ì¹ç¤Ë¡¢¤½¤ì¤òÊѹ¹¤¹¤ë¤¿¤á¤Î +`tramp-methods' ¤È¤¤¤¦ÊÑ¿ô¤¬¤¢¤ê¤Þ¤¹¡£ + + Êѹ¹¤¬É¬Íפˤʤä¿»þ¤Î¤¿¤á¤Ë¡¢¤³¤ÎÊÑ¿ô¤Î Lisp +¥É¥­¥å¥á¥ó¥È¤Ë¤Ä¤¤¤Æ½Ò¤Ù¤Æ ¤ª¤­¤Þ¤¹¡£¥É¥­¥å¥á¥ó¥È¤Ï `C-h v +tramp-methods ' ¤Ç»²¾È¤¹¤ë ¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Customizing Completion, Next: Remote Programs, Prev: Customizing Methods, Up: Configuration + +4.7 ¥æ¡¼¥¶/¥Û¥¹¥È̾Êä´°¤Î¤¿¤á¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ÎÁªÂò +================================================= + +ÊÑ¿ô `tramp-completion-function-alist' ¤Ï¡¢¥æ¡¼¥¶Ì¾¤È¥Û¥¹¥È̾¤Î Êä´° +(*note Filename completion::) ¤ÎºÝ¤Ë¤É¤Î¥Õ¥¡¥¤¥ë¤¿¤Á¤ò¹Íθ¤ËÆþ¤ì +¤ë¤«¤ò¥«¥¹¥¿¥Þ¥¤¥º¤¹¤ë¤¿¤á¤Ë¤¢¤ê¤Þ¤¹¡£¤³¤ÎÊÑ¿ô¤Ï³Æ¡¹¤Î¥á¥½¥Ã¥É¤ËÂФ·¤Æ¡¢ +ÀßÄê¥Õ¥¡¥¤¥ë¤Î½¸¹ç¤È¤½¤Î¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤Ç¤­¤ë Lisp ´Ø¿ô¤È¤ÎÁȤòÊÝ»ý¤· +¤Þ¤¹¡£`tramp-completion-function-alist' ¤Î¥¨¥ó¥È¥ê¤Ï (METHOD PAIR1 +PAIR2 ...) ¤Î·Á¼°¤ò¤È¤ê¤Þ¤¹¡£ + + ¤½¤ì¤¾¤ì¤Î PAIR ¤Ï (FUNCTION FILE) ¤«¤éÀ®¤ê¤Þ¤¹¡£ FUNCTION +¤ÏÊä´°¤ÎºÝ¤Ë FILE ¤«¤é¥æ¡¼¥¶Ì¾¤È¥Û¥¹¥È̾¤ò¼è¤ê½Ð +¤¹¤Î¤Ë»È¤ï¤ì¤Þ¤¹¡£¤³¤ÎÊÑ¿ô¤Ë¥¢¥¯¥»¥¹¤¹¤ëÆó¤Ä¤Î´Ø¿ô¤¬¤¢¤ê¤Þ¤¹: + + -- Function: tramp-get-completion-function method + ¤³¤Î´Ø¿ô¤Ï METHOD ¤ËÂФ¹¤ëÊä´°´Ø¿ô¤Î¥ê¥¹¥È¤òÊÖ¤·¤Þ¤¹¡£ + + Example: + (tramp-get-completion-function "rsh") + + => ((tramp-parse-rhosts "/etc/hosts.equiv") + (tramp-parse-rhosts "~/.rhosts")) + + -- Function: tramp-set-completion-function method function-list + ¤³¤Î´Ø¿ô¤Ï METHOD ¤ËÂФ¹¤ëÊä´°´Ø¿ô¤Î¥ê¥¹¥È¤ò FUNCTION-LIST + ¤ËÀßÄꤷ¤Þ¤¹¡£ + + Example: + (tramp-set-completion-function "ssh" + '((tramp-parse-sconfig "/etc/ssh_config") + (tramp-parse-sconfig "~/.ssh/config"))) + + => ((tramp-parse-sconfig "/etc/ssh_config") + (tramp-parse-sconfig "~/.ssh/config")) + + ÀßÄê¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤¹¤ë¤¿¤á¤Î°Ê²¼¤Î´Ø¿ô¤¬¤¢¤é¤«¤¸¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹: + +`tramp-parse-rhosts' + ¤³¤Î´Ø¿ô¤Ï¹½Ê¸Åª¤Ë `~/.rhosts' ¤ÈÅù²Á¤Ê¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤·¤Þ¤¹¡£¤â¤· + ½ñ¤«¤ì¤Æ¤¤¤ì¤Ð¥Û¥¹¥È̾¤È¥æ¡¼¥¶Ì¾¤ÎξÊý¤òÊÖ¤·¤Þ¤¹¡£ + +`tramp-parse-shosts' + ¤³¤Î´Ø¿ô¤Ï¹½Ê¸Åª¤Ë `~/.ssh/known_hosts' + ¤ÈÅù²Á¤Ê¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤·¤Þ¤¹¡£ + ¤½¤Î¥Õ¥¡¥¤¥ë¤Ë¤Ï¥æ¡¼¥¶Ì¾¤Ï½ñ¤«¤ì¤Æ¤¤¤Ê¤¤¤Î¤Ç¥Û¥¹¥È̾¤Î¤ß¤òÊÖ¤·¤Þ¤¹¡£ + +`tramp-parse-sconfig' + ¤³¤Î´Ø¿ô¤Ï `~/.ssh/config' ·Á¼°¤Î¥Õ¥¡¥¤¥ë¤Î `Host' ¥¨¥ó¥È¥ê¤Ç + ÄêµÁ¤µ¤ì¤¿¥Û¥¹¥È¤Î¤¢¤À¤Ê¤òÊÖ¤·¤Þ¤¹¡£ + +`tramp-parse-hosts' + `/etc/hosts' + ·Á¼°¤Î¥Õ¥¡¥¤¥ë¤Î¤¿¤á¤Î´Ø¿ô¤Ç¤¹¡£¥Û¥¹¥È̾¤Î¤ß¤òÊÖ¤·¤Þ¤¹¡£ + +`tramp-parse-passwd' + `/etc/passwd' + ¤Î¤è¤¦¤Ê¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤¹¤ë´Ø¿ô¤Ç¤¹¡£ÅöÁ³¤Ê¤¬¤é¥æ¡¼¥¶ + ̾¤Î¤ß¤òÊÖ¤·¤Þ¤¹¡£ + +`tramp-parse-netrc' + ºÇ¸å¤Ë¡¢¤³¤ì¤Ï `~/.netrc' ¤Î¤è¤¦¤Ê¥Õ¥¡¥¤¥ë¤ò¥Ñ¡¼¥¹¤¹¤ë´Ø¿ô¤Ç¤¹¡£ + +¤â¤·ÆÈ¼«¤Î¥Ç¡¼¥¿¤òÆÈ¼«¤Î¹½Â¤¤Ç¥Õ¥¡¥¤¥ë¤ËÊÝ»ý¤·¤¿¤¤¤Ê¤é¡¢¤³¤Î¤è¤¦¤Ê´Ø¿ô +¤òÄ󶡤¹¤ì¤Ð¤è¤¤¤Ç¤¹¡£¤³¤Î´Ø¿ô¤Ï°Ê²¼¤Î´·½¬¤Ë¹çÃפ¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£ + + -- Function: my-tramp-parse file + FILE ¤Ï¤¢¤Ê¤¿¤Î¥Û¥¹¥È¤Ë¤¢¤ë¥Õ¥¡¥¤¥ë̾¤â¤·¤¯¤Ï `nil' ¤Î¤¤¤º¤ì¤« + ¤Ç¤¹¡£¤³¤Î´Ø¿ô¤Ï (USER HOST) ¤Î¥ê¥¹¥È¤òÊÖ¤µ¤Í¤Ð¤Ê¤ê¤Þ¤»¤ó¡£ + ¤½¤ì¤é¤Ï¥æ¡¼¥¶/¥Û¥¹¥È̾Êä´°¤Î¸õÊä¤È¤·¤Æ»È¤ï¤ì¤Þ¤¹¡£ + + Example: + (my-tramp-parse "~/.my-tramp-hosts") + + => ((nil "toto") ("daniel" "melancholia")) + + +File: tramp_ja.info, Node: Remote Programs, Next: Remote shell setup, Prev: Customizing Completion, Up: Configuration + +4.8 ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç TRAMP ¤¬¥×¥í¥°¥é¥à¤òȯ¸«¡¢»ÈÍѤ¹¤ëÊýË¡ +============================================================= + +TRAMP ¤Ï¥ê¥â¡¼¥È¥Û¥¹¥È¾å¤Î¤¤¤¯¤Ä¤«¤Î¥×¥í¥°¥é¥à¡¢`ls'¡¢ `test'¡¢`find' +¤½¤·¤Æ `cat' ¤Ë°Í¸¤·¤Æ¤¤¤Þ¤¹¡£ + +¤³¤ì¤é¤Î¥Ä¡¼¥ë¤Ë¤¯¤ï¤¨¡¢¥³¥Í¥¯¥·¥ç¥ó¥á¥½¥Ã¥É¤Î¤¿¤á¤Ë¤¤¤¯¤Ä¤«¤Î¥Ä¡¼¥ë¤¬ +ɬÍפǤ¹¡£¾ÜºÙ¤Ï *Note Inline methods:: ¤È *Note External transfer +methods:: ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£ + + ¤¤¤¯¤Ä¤«¤Î¾¤Î¥Ä¡¼¥ë¡¢`perl' (¤¢¤ë¤¤¤Ï `perl5') ¤È `grep' +¤¬Â¸ºß¤¹¤ì¤Ð¤½¤ì¤é¤â»ÈÍѤµ¤ì¤Þ¤¹¡£¤³¤ì¤Ï¡¢À­Ç½¤È +¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¥¢¥¯¥»¥¹¤ÎÀµ³Î¤µ¤Î¸þ¾å¤Î¤¿¤á¤Ç¤¹¡£ + + TRAMP +¤Ï¥ê¥â¡¼¥È¥Þ¥·¥ó¤ËÀܳ¤·¤¿»þ¤Ë¡¢»ÈÍѲÄǽ¥×¥í¥°¥é¥à¤ò¸¡º÷¤·¤Þ¤¹¡£ ÊÑ¿ô +TRAMP-REMOTE-PATH ¤Ï¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç¸¡º÷¤µ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê +¤òÀ©¸æ¤·¤Þ¤¹¡£ + + ¥Ç¥Õ¥©¥ë¥È¤Ç¿¤¯¤Î¥Þ¥·¥ó¤Ë¤È¤Ã¤ÆÅ¬Àڤʥѥ¹¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹¡£¤·¤«¤· +¤Ê¤¬¤é¡¢¥í¡¼¥«¥ë(¤¢¤ë¤¤¤Ï¥ê¥â¡¼¥È)¥·¥¹¥Æ¥à¤Î´ÉÍý¼Ô¤¬¡¢É¬Íפʥġ¼¥ë¤ò +¤Ø¤ó¤Ô¤Ê¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥¤¥ó¥¹¥È¡¼¥ë¤·¤Æ¤¤¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£ + + ¤³¤Î¤è¤¦¤Ê¾ì¹ç¤Ç¤â TRAMP ¤ò»È¤¦»ö¤¬¤Ç¤­¤Þ¤¹¡£Ã±¤Ë¡¢É¬Íפʥǥ£¥ì¥¯¥È¥ê +¤ò¥ê¥â¡¼¥È¥Ñ¥¹¤ËÄɲ乤륳¡¼¥É¤ò `.emacs' ¤Ë½ñ¤¯¤À¤±¤Ç¤¹¡£¤³¤ì¤Ç +Àܳ»þ¤Ë TRAMP ¤Ë¤è¤ê¡¢Äɲä·¤¿¥Ç¥£¥ì¥¯¥È¥ê¤¬¸¡º÷¤µ¤ì¥×¥í¥°¥é¥à¤¬ +ȯ¸«¤µ¤ì¤Þ¤¹¡£ + + ¥ê¥â¡¼¥È¥µ¡¼¥Á¥Ñ¥¹¤Ë¥Ç¥£¥ì¥¯¥È¥ê¤òÄɲ乤뤿¤á¤Ë¤Ï¡¢°Ê²¼¤Î¤è¤¦¤Ê +¥³¡¼¥É¤ò»È¤Ã¤Æ¤¯¤À¤µ¤¤: + + ;; ÊÑ¿ô¤òÄêµÁ¤¹¤ë¤¿¤á¤Ë TRAMP ¤ò¥í¡¼¥É¤¹¤ë + (require 'tramp) + ;; `perl' ¤¬ "/usr/local/perl/bin" ¤Ë¤¢¤ë + (add-to-list 'tramp-remote-path "/usr/local/perl/bin") + + +File: tramp_ja.info, Node: Remote shell setup, Next: Windows setup hints, Prev: Remote Programs, Up: Configuration + +4.9 ¥ê¥â¡¼¥È¥·¥§¥ë¤ÎÀßÄê¤Î¥Ò¥ó¥È +================================ + +*Note Overview:: ¤ÎÀá¤ÇÀâÌÀ¤·¤¿¤è¤¦¤Ë¡¢TRAMP ¤Ï¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÀܳ¤·¡¢ +¤½¤³¤Ë¤¢¤ë¥·¥§¥ë¤ÈÂÐÏä·¤Þ¤¹¡£¤â¤Á¤í¤ó¥í¥°¥¤¥ó¤¹¤ëºÝ¤Ë¤Ï¥·¥§¥ë¤Ï¤½¤Î +½é´ü²½¥Õ¥¡¥¤¥ë¤ò¼Â¹Ô¤·¤Þ¤¹¡£Î㤨¤Ð¤¢¤Ê¤¿¤Î½é´ü²½¥Õ¥¡¥¤¥ë¤¬¤¢¤Ê¤¿¤Î¤ªÊì +¤µ¤ó¤ÎÃÂÀ¸Æü¤òÆþÎϤµ¤»¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤¿¤È¤·¤Þ¤·¤ç¤¦; ÅöÁ³ TRAMP +¤Ï¤½¤Î¤³¤È¤òÃΤé¤Ê¤¤¤Î¤Ç¡¢¤½¤Î¥Û¥¹¥È¤Ø¤Î¥í¥°¥¤¥ó¤Ë¼ºÇÔ¤·¤Þ¤¹¡£ + + ¤³¤ÎÌäÂê¤òÄɵ᤹¤ë¤¿¤á¤Ë¡¢¤¤¤¯¤Ä¤«¤ÎÀïά¤¬¹Í¤¨¤é¤ì¤Þ¤¹¡£°ì¤Ä¤Ï¡¢TRAMP +¤¬¤¹¤Ù¤Æ¤Î²Äǽ¤Ê¾õ¶·¤ËÂбþ¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¤³¤È¤Ç¤¹¡£¤³¤ì¤Ï¾ÃÌ×Àï¤Ç¤¹¡£ +²¿¸Î¤Ê¤é _Á´¤Æ¤Î_ ¾õ¶·¤ò°·¤¦¤³¤È¤ÏÉÔ²Äǽ¤À¤«¤é¤Ç¤¹¡£Ê̤μê¤È¤·¤Æ¡¢ +TRAMP ¤Î´üÂÔÄ̤ê¤Ë¿¶¤ëÉñ¤¦¤è¤¦¤Ë¡¢¤¢¤Ê¤¿¤Ë¥ê¥â¡¼¥È¥Û¥¹¥È¤ÎÀßÄê¤ò¤·¤Æ +¤¤¤¿¤À¤¯¤È¤¤¤¦¤³¤È¤â½ÐÍè¤Þ¤¹¡£¤·¤«¤·¤³¤ì¤ÏÉÔÊØ¤«¤â¤·¤ì¤Þ¤»¤ó¡£²¿¸Î¤Ê¤é +TRAMP ¤ò»È¤¤»Ï¤á¤ë¤è¤êÀè¤Ë¡¢¥·¥§¥ë¤ÎÀßÄê¤Ë¿¤¯¤ÎÏ«ÎϤò³ä¤¯É¬Íפ¬¤¢¤ë +¤Î¤Ç¤¹¤«¤é¡£ + + ¤½¤Î¤³¤È¤«¤é¡¢¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Ç¤Ï¤½¤ì¤é¤òÁȤ߹ç¤ï¤»¤¿ÊýË¡¤ò¤È¤ê¤Þ¤¹¡£ +¤¤¤¯¤Ä¤«¤Î¤¢¤ê¤Õ¤ì¤¿ÀßÄê¤Ë¤Ä¤¤¤Æ¤ÏÍý²ò¤·¤è¤¦¤È¤·¤Æ¤¯¤ì¤Æ¡¢¤¢¤Ê¤¿¤Ë¤Ï +ËÜÅö¤ËÆÃ°Û¤ÊÀßÄê¤À¤±¤òÈò¤±¤ë¤è¤¦¤Ëµá¤á¤Þ¤¹¡£Î㤨¤Ð¡¢¥ê¥â¡¼¥È¥Û¥¹¥È¾å¤Ç +¤¢¤ë¥×¥í¥°¥é¥à¤ò¸«¤Ä¤±¤ë¤¿¤á¤Ë¤Ï¡¢¥Ç¥£¥ì¥¯¥È¥ê¤Î°ìÍ÷¤òÄ´¤Ù¤Þ¤¹¡£ +¤½¤·¤Æ¤Þ¤¿¡¢¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¤ò¤É¤¦¤«Ä´¤Ù¤ëÊýË¡¤È¤¤¤¦¤Î¤âÌÀ¤é¤«¤Ç¤Ï +¤Ê¤¤¤Î¤Ç¡¢¤¤¤¯¤Ä¤«¤Î°Û¤Ê¤ë²ÄǽÀ­¤ò»î¤·¤Æ¤¯¤ì¤Þ¤¹¡£ +(¤¢¤ë¥Û¥¹¥È¤È¥·¥§¥ë¤Ë¤ª¤¤¤Æ¤Ï¡¢`test -e' ¥³¥Þ¥ó¥É¤¬¤½¤ÎÌòÌܤò²Ì¤¿¤¹¡£ +Ê̤Υۥ¹¥È¡¢¥·¥§¥ë¤ËÂФ·¤Æ¤Ï¥·¥§¥ë¤ÎÁȤ߹þ¤ß¥³¥Þ¥ó¥É¤ÏƯ¤«¤Ê¤¤¤¬¡¢ +`/usr/bin/test -e' ¤ä `/bin/test -e' ¤Ê¤é¤¦¤Þ¤¯Æ¯¤¯¡£ +¤½¤·¤Æ¤µ¤é¤ËÊ̤Υۥ¹¥È¤Ç¤Ï `ls -d' ¤¬¤½¤ÎÊýË¡¤È¤·¤ÆÆ¯¤¯¡£) + + °Ê²¼¤Ç¤Ï¡¢TRAMP +¤¬¼è¤ê°·¤Ã¤Æ¤¯¤ì¤Ê¤¤¡¢¤Ä¤Þ¤ê¤¢¤Ê¤¿¤¬Àµ¤·¤¯ÀßÄꤹ¤ëɬÍ× +¤Î¤¢¤ë¤¤¤¯¤Ä¤«¤Î»öÊÁ¤Ë¤Ä¤¤¤Æ½Ò¤Ù¤Þ¤¹¡£ + +SHELL-PROMPT-PATTERN + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤·¤¿¸å¡¢TRAMP + ¤¬¥ê¥â¡¼¥È¥·¥§¥ë¤ËÌ¿Îá¤òÁ÷¤ì¤ë + ¤è¤¦¤Ë¤Ê¤ëÁ°¤Ë¡¢¥ê¥â¡¼¥È¥·¥§¥ë¤Î¥»¥Ã¥È¥¢¥Ã¥×¤¬½ªÎ»¤¹¤ë¤Î¤òÂÔ¤ÄɬÍפ¬¤¢¤ê + ¤Þ¤¹¡£¥·¥§¥ë¥×¥í¥ó¥×¥È¤òǧ¼±¤¹¤ë°Ù¤Ë¡¢ÊÑ¿ô `shell-prompt-pattern' + ¤ò¥ê¥â¡¼¥È¥Û¥¹¥È¤Î¥·¥§¥ë¥×¥í¥ó¥×¥È¤òǧ¼±½ÐÍè¤ë¤è¤¦¤ËÀßÄꤷ¤Æ¤ª¤¯É¬Íפ¬ + ¤¢¤ê¤Þ¤¹¡£ + + TRAMP ¤Ï `shell-prompt-pattern' ¤ËÂФ·¤Æ¥Ð¥Ã¥Õ¥¡ËöÈø¤Ç¥Þ¥Ã¥Á¤¹ + ¤ë¤³¤È¤òÍ׵᤹¤ë¤³¤È¤ËÃí°Õ¤·¤Æ²¼¤µ¤¤¡£Â¿¤¯¤Î¿Í¤Ï¤³¤ÎÊÑ¿ô¤ÎÃͤȤ·¤Æ¼¡¤Î + ¤è¤¦¤Ê¤â¤Î¤ò»ØÄꤷ¤Æ¤¤¤Þ¤¹: `"^[^>$][>$] *"'¡£¤³¤³¤Ç¤¢¤Ê¤¿¤Î¥·¥§¥ë + ¥×¥í¥ó¥×¥È¤¬ `a c $ ' + ¤Î¤è¤¦¤Ê¤â¤Î¤À¤Ã¤¿¤È¤·¤Þ¤·¤ç¤¦¡£¤³¤Î¾ì¹ç¡¢ TRAMP ¤Ïʸ»ú`>' + ¤ò¥×¥í¥ó¥×¥È¤Î½ªÃ¼¤Èǧ¼±¤·¤Þ¤¹¤¬¡¢¤½¤ì¤Ï¥Ð¥Ã¥Õ¥¡ + ¤Î½ªÃ¼¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó¡£ + +TRAMP-SHELL-PROMPT-PATTERN + ¤³¤ÎÀµµ¬É½¸½¤Ï `shell-prompt-pattern' ¤ÈƱÍͤ˥ê¥â¡¼¥È¥·¥§¥ë¤Î + ¥×¥í¥ó¥×¥È¤Ë¥Þ¥Ã¥Á¤¹¤ë¤â¤Î¤È¤·¤Æ»È¤ï¤ì¤Þ¤¹¡£¤³¤ÎÆó¤ÄÌܤÎÊÑ¿ô¤Ï¥ê¥â¡¼¥È + ¥·¥§¥ë¤Î¥×¥í¥ó¥×¥È¤¬¥í¡¼¥«¥ë¥·¥§¥ë¤È°Û¤Ê¤ë²ÄǽÀ­¤¬¤¢¤ë¤Î¤Ç¸ºß¤·¤Þ¤¹¡£ + ¤È¤Ë¤«¤¯ TRAMP ¤ÎÍ×ÅÀ¤Ï¥ê¥â¡¼¥È¥Û¥¹¥È¤ËÊ̤Υ桼¥¶¤È¤·¤Æ¥í¥°¥¤¥ó¤¹¤ë + ¤³¤È¤Ç¤¹¡£`tramp-shell-prompt-pattern' ¤Î¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï + `shell-prompt-pattern' ¤Î¥Ç¥Õ¥©¥ë¥ÈÃÍ¤ÈÆ±°ì¤Î¤â¤Î¤Ç¤¹¤¬¡¢Â¿¤¯¤Î¾õ¶· + ¤Ç¤½¤ì¤Ï¤¦¤Þ¤¯Æ¯¤¯¤ÈÊó¹ð¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ + +`tset' ¤È¤½¤Î¾¤Î¼ÁÌä + ¥·¥§¥ë¤Îµ¯Æ°¥¹¥¯¥ê¥×¥È¤«¤é `tset' ¥×¥í¥°¥é¥à¤ò¸Æ¤Ó½Ð¤·¡¢ + ¥·¥§¥ë¤ÎüËö¤Î¼ïÎà¤ò¿Ò¤Í¤ë¤è¤¦¤Ë¤·¤Æ¤¤¤ë¾ì¹ç¤¬¤¢¤ê¤Þ¤¹¡£¤¿¤Ö¤ó + ¥·¥§¥ë¤Ë¤è¤Ã¤Æ¤Ï¤½¤Î¾¤Î¼ÁÌä¤òµ¯Æ°»þ¤Ë¤·¤Æ¤¯¤ë¾ì¹ç¤â¤¢¤ë¤Ç¤·¤ç¤¦¡£ + TRAMP ¤Ï¤³¤ì¤é¤Î¼ÁÌä¤ËÅú¤¨¤ëÊýË¡¤òÃΤê¤Þ¤»¤ó¡£¤³¤ÎÌäÂê¤ò°·¤¦¤Ë¤Ï + Æó¤Ä¤Î¥¢¥×¥í¡¼¥Á¤¬¤¢¤ê¤Þ¤¹¡£°ì¤Ä¤Î¥¢¥×¥í¡¼¥Á¤Ï¡¢¥·¥§¥ë¤¬ TRAMP ¤«¤é + ¸Æ¤Ó½Ð¤µ¤ì¤¿¤È¤­¤Ë²¿¤Î¼ÁÌä¤â¤·¤Ê¤¤¤è¤¦¤Ë¤·¤Æ¤ª¤¯¤³¤È¤Ç¤¹¡£¤½¤Î¤¿¤á¤Ë¤Ï + ´Ä¶­ÊÑ¿ô `TERM' ¤òÄ´¤Ù¤Æ²¼¤µ¤¤¡£¤½¤ì¤ÏÀܳ»þ¤Ë `dumb' ¤ËÀßÄê + ¤µ¤ì¤Þ¤¹¡£ + + ÊÑ¿ô `tramp-terminal-type' ¤Ë¤è¤ê¤³¤ÎÃͤò `dumb' ¤ËÊѹ¹¤¹¤ë + ¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + Ê̤Υ¢¥×¥í¡¼¥Á¤Ï TRAMP ¤Ë¤³¤ì¤é¤Î¼ÁÌä¤ò¶µ¤¨¤Æ¤ª¤¯¤³¤È¤Ç¤¹¡£ÊÑ¿ô + `tramp-actions-before-shell' ¤ª¤è¤Ó `tramp-multi-actions' + (¥Þ¥ë¥Á¥Û¥Ã¥×Àܳ¤Î¾ì¹ç) ¤ò»²¾È¤·¤Æ²¼¤µ¤¤¡£ + +`.profile' Ãæ¤Î´Ä¶­ÊÑ¿ô¤Ç¡¢¥æ¡¼¥¶¤ÈƱ¤¸Ì¾Á°¤Î¤â¤Î¤¿¤Á + frumple ¤È¤¤¤¦Ì¾Á°¤Î¥æ¡¼¥¶¤¬µï¤¿¤È¤·¤Æ¡¢ÊÑ¿ô `FRUMPLE' ¤ò¥·¥§¥ë´Ä¶­ + ¤ÇÀßÄꤷ¤Æ¤¤¤ë¾ì¹ç¡¢ÉÔ¶ñ¹ç¤¬µ¯¤­¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£ `FRUMPLE_DIR' + ¤È¤«¤½¤Î¤è¤¦¤Ê¤â¤Î¤Ë²þ̾¤¹¤ë¤Î¤¬¤è¤¤¤Ç¤·¤ç¤¦¡£ + + ´ñ̯¤Ê¸ú²Ì¤¬¼ÂºÝ¤Ë TRAMP ¥æ¡¼¥¶¤«¤éÊó¹ð¤µ¤ì¤Æ¤¤¤Þ¤¹! + +`.profile' Ãæ¤Î Non-Bourne ¥³¥Þ¥ó¥É¤¿¤Á + ¥ê¥â¡¼¥È¥Û¥¹¥È¤Ë¥í¥°¥¤¥ó¤·¤¿¸å¡¢TRAMP ¤Ï¥³¥Þ¥ó¥É `exec /bin/sh' + ¤òȯ¹Ô¤·¤Þ¤¹¡£ (¼ÂºÝ¤Ë¤Ï¥³¥Þ¥ó¥É¤Ï¤Á¤ç¤Ã¤È°Û¤Ê¤ê¤Þ¤¹¤¬¡£) + `/bin/sh' + ¤¬¼Â¹Ô¤µ¤ì¤ë»þ¤Ë¡¢¤¤¤¯¤Ä¤«¤Î½é´ü²½¥Õ¥¡¥¤¥ë¤¬ÆÉ¤ß¹þ¤Þ¤ì¤Þ¤¹¡£ + Î㤨¤Ð `~/.shrc' ¤ä `~/.profile' ¤Ç¤¹¡£ + + ¤³¤³¤Ç¡¢¥í¥°¥¤¥ó¥·¥§¥ë¤¬ `/bin/sh' ¤Ç¤Ï¤Ê¤¯¡¢ bash ¤ä ksh ¤È¤¤¤Ã¤¿ + Bourne Ū¤Ê¥·¥§¥ë¤Ç¤¢¤Ã¤¿¾ì¹ç¡¢¿Í¤Ë¤è¤Ã¤Æ¤Ï `~/.shrc' ¤ä + `~/.profile'. + ¤Ë¥·¥§¥ë¤ÎÀßÄê¤ò½ñ¤¤¤Æ¤¤¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤½¤Î¾ì¹ç¤Ë¡¢Bourne + ¤Ç¤Ê¤¤¹½À®Êª + ¤¬¤½¤ì¤é¤Î¥Õ¥¡¥¤¥ë¤Ë½ñ¤«¤ì¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£¤½¤¦¤¹¤ë¤È¡¢`exec + /bin/sh' ¤Ë¤è¤Ã¤Æ Bourne ¥·¥§¥ë¤Ï¤½¤ì¤é¤òÌᤷ¤Æ¤·¤Þ¤¤¤Þ¤¹¡£ + + Î㤨¤Ð `~/.profile' ¥Õ¥¡¥¤¥ë¤Ë `export FOO=bar' ¤È½ñ¤¤¤Æ¤¢¤Ã¤¿ + ¤È¤¹¤ë¤È¡¢É¸½àŪ¤Ê Bourne + ¥·¥§¥ë¤Ï¤³¤Î¹½Ê¸¤òÍý²ò¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢¤³¤Î¹Ô¤Ë + Åþ㤹¤ë¤È¥·¥ó¥¿¥Ã¥¯¥¹¥¨¥é¡¼¤òÊÖ¤·¤Þ¤¹¡£ + + Ê̤ÎÎã¤È¤·¤Æ¤Ï¥Á¥ë¥À (`~') ʸ»ú¤¬¤¢¤ê¤Þ¤¹¡£Î㤨¤Ð `$PATH' ¤Ë + `~/bin' ¤òÉÕ¤±²Ã¤¨¤ë¾ì¹ç¤Ç¤¹¡£ ¿¤¯¤Î Bourne ¥·¥§¥ë¤Ï¤³¤Îʸ»ú¤òŸ³« + ¤»¤º¡¢ÉáÄ̤Ï̾Á°¤¬¥Á¥ë¥À°ìʸ»ú¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ï¸ºß¤·¤Ê¤¤¤Î¤Ç¤ª¤«¤·¤Ê¤³¤È + ¤¬µ¯¤³¤ë¤Ç¤·¤ç¤¦¡£ + + ¤³¤ì¤ËÂФ·¤Æ²¿¤ò¤¹¤ì¤Ð¤è¤¤¤Î¤«? + + °ì¤Ä¤ÎÊýË¡¤È¤·¤Æ¤ÏÁ´¤Æ¤Î¥ê¥â¡¼¥È¥Û¥¹¥È¾å¤Î `~/.shrc' ¤È + `~/.profile' ¤ÎÃæ¤ÎÁ´¤Æ¤¬ Bourne-¸ß´¹¤Ç¤¢¤ë¤è¤¦¤Ë¤¹¤ë¤³¤È¤Ç¤¹¡£ + ¾å¤ÎÎã¤Ç¤Ï¡¢`export FOO=bar' ¤ÎÂå¤ï¤ê¤Ë `FOO=bar; export FOO' + ¤È½ñ¤±¤Ð¤è¤¤¤Ç¤·¤ç¤¦¡£ + + Ê̤ÎÊýË¡¤È¤·¤Æ¤Ï¡¢non-Bourne + ¥·¥§¥ë¤ÎÀßÄê¤òÊ̤Υե¡¥¤¥ë¤Ë½ñ¤¯¤³¤È¤Ç¤¹¡£ Î㤨¤Ð¡¢bash ¤Ï¥Õ¥¡¥¤¥ë + `~/.bash_profile' ¤¬¤¢¤ì¤Ð `~/.profile' + ¤ÎÂå¤ï¤ê¤Ë¤½¤ì¤òÆÉ¤ß¹þ¤ß¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ bash + ¥Õ¥¡¥ó¤ÏÁ´¤Æ¤Î¥ê¥â¡¼¥È¥Û¥¹¥È ¾å¤Î `~/.profile' ¤ò + `~/.bash_profile' ¤Ë²þ̾¤·¤Æ¤ª¤±¤ÐÂç¾æÉפǤ¹¡£ + + TRAMP + ¤Î³«È¯¼Ô¤Ï¤³¤ÎÌäÂê¤ò²óÈò¤·¤¿¤¤¤È¹Í¤¨¤Æ¤¤¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ¤³¤ì¤Ë + ´Ø¤¹¤ë¥¢¥¤¥Ç¥¢¤¬¤¢¤ì¤Ð¤¼¤Ò¶µ¤¨¤Æ²¼¤µ¤¤¡£¤·¤«¤·¤Ê¤¬¤é¡¢¤³¤ì¤Ï¤½¤¦Ã±½ã¤Ç¤Ï + ¤Ê¤¤¤È¹Í¤¨¤Æ¤¤¤Þ¤¹: `exec /bin/sh' ¤È¸Æ¤ÖÁ°¤Ë¤Ï¡¢TRAMP ¤Ï¤É¤Î + ¼ïÎà¤Î¥·¥§¥ë¤ÈÂÐÏ䷤Ƥ¤¤ë¤Î¤«ÃΤé¤Ê¤¤¤Î¤Ç¤¹¡£¤½¤ì¤Ï ksh ¤ä bash + ¤È¤¤¤Ã¤¿ Bourne Ū¤Ê¥·¥§¥ë¤Ç¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¤·¡¢csh ¤«¤éÇÉÀ¸¤·¤¿ + tcsh ¤Î¤è¤¦¤Ê ¤â¤Î¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤â¤·¤¯¤Ï zsh ¤ä¡¢¤Ï¤¿¤Þ¤¿ rc + ¤Ç¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£ ¤â¤·¥·¥§¥ë¤¬¤¹¤Ç¤Ë Bourne + Ū¤Ê¤â¤Î¤Ç¤¢¤ë¤Ê¤é `exec /bin/sh' ¤ÎÃʳ¬¤ò + ¾Êά¤¹¤ë¤Î¤¬·üÌ¿¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤·¤«¤·¡¢¤É¤¦¤ä¤Ã¤Æ¥·¥§¥ë¤¬ Bourne + Ū¤À¤È ÃΤë¤Î¤Ç¤·¤ç¤¦¤«? + + + +File: tramp_ja.info, Node: Auto-save and Backup, Prev: Windows setup hints, Up: Configuration + +4.10 Auto-save ¤È¥Ð¥Ã¥¯¥¢¥Ã¥×¤ÎÀßÄê +=================================== + +auto-save ¤ÎÀâÌÀ¤Ï̤´°À®¤Ç¤¹¡£ + + Ä̾ï Emacs ¤Ï¥ª¥ê¥¸¥Ê¥ë¤Î¥Õ¥¡¥¤¥ë¤ÈƱ¤¸¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡ +¥¤¥ë¤òÊݸ¤·¤Þ¤¹¤¬¡¢¤³¤Îµóư¤ÏÊÑ¿ô `backup-directory-alist' ¤òÄÌ +¤·¤ÆÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£TRAMP ¤òÍѤ¤¤¿Àܳ¤Ë¤ª¤¤¤Æ¤³¤Î¤³¤È¤Ïͽ +´ü¤·¤Ê¤¤ÉûºîÍѤò¤â¤¿¤é¤¹²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£Î㤨¤ÐÁ´¤Æ¤Î¥Ð¥Ã¥¯¥¢¥Ã¥×¤¬¥Ç +¥£¥ì¥¯¥È¥ê `~/.emacs.d/backups/' ¤Ë¹Ô¤¯¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤¿¤È¤·¤Æ¡¢¥Õ +¥¡¥¤¥ë `/su:root@localhost:/etc/secretfile' ¤òÊÔ½¸¤·¤¿¤È¤·¤Þ¤·¤ç +¤¦¡£¤½¤Î·ë²Ì¤Ï¡¢¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤Ï root ¤Ç¤Ï¤Ê¤¯¤¢¤Ê¤¿¤Î½êÍ­¤È¤Ê¤ê¡¢ +¤·¤¿¤¬¤Ã¤Æ¤¿¤È¤¨¤½¤Î¤Ä¤â¤ê¤¬¤Ê¤«¤Ã¤¿¤È¤·¤Æ¤â¤½¤ì¤¬Â¾¼Ô¤«¤é¸«¤Æ¤·¤Þ¤¦²Ä +ǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£ + + `backup-directory-alist' ¤¬ nil (¥Ç¥Õ¥©¥ë¥È) ¤Ç¤¢¤ì¤Ð¤½¤Î¤è¤¦¤ÊÌä +Âê¤Ï¤ª¤³¤ê¤Þ¤»¤ó¡£ + + ¤â¤·¤¢¤Ê¤¿¤¬¤½¤ÎÊÑ¿ô¤ò¥«¥¹¥¿¥Þ¥¤¥º¤·¤¿¤¤¤Ê¤é¡¢TRAMP ¤Î¥Õ¥¡¥¤¥ë¤ËÂÐ +¤·¤ÆÆÃÊ̤ÊÀßÄê¤ò¹Ô¤Ê¤¦¤È¤¤¤¦²óÈòË¡¤¬¤¢¤ê¤Þ¤¹¡£Î㤨¤Ð°Ê²¼¤Îµ­½Ò¤Ë¤è¤ê¡¢ +TRAMP ¤Î¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ¸ú²ÌŪ¤Ë `backup-directory-alist' ¤Î¸ú +²Ì¤ò¾Ã¤·¤Þ¤¹: + + (require 'tramp) + (add-to-list 'backup-directory-alist + (cons tramp-file-name-regexp nil)) + + +File: tramp_ja.info, Node: Windows setup hints, Next: Auto-save and Backup, Prev: Remote shell setup, Up: Configuration + +4.11 Cygwin ssh ¤Ë¤Þ¤Ä¤ï¤ë»öÊÁ +============================== + +¤³¤ÎÀá¤Ï¤¿¤¯¤µ¤ó¤Î»Å»ö¤¬É¬ÍפǤ¹! ¤É¤¦¤«¼êÅÁ¤Ã¤Æ²¼¤µ¤¤¡£ + + ¤â¤·¤¢¤Ê¤¿¤¬ Cygwin ¤Ç¥¤¥ó¥¹¥È¡¼¥ë¤·¤¿ ssh +(¥¤¥ó¥¹¥È¡¼¥é¤ÇÌÀ¼¨Åª¤ËÁªÂò ¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹) +¤ò»È¤Ã¤Æ¤¤¤ë¤Ê¤é¡¢Àܳ¥á¥½¥Ã¥É¤È¤·¤Æ `sshx' ¤ò +ÁªÂò¤¹¤ë¤À¤±¤Ç¥Þ¥·¥ó¤Î³°¤Ë½Ð¤é¤ì¤ë¤Ï¤º¤Ç¤¹¡£Cygwin ¤Î¥»¥Ã¥È¥¢¥Ã¥×¤Ë +¤Ä¤¤¤Æ¤Î¾ðÊó¤Ï `http://cygwin.com/faq/' ¤Ë¤¢¤ëÈà¤é¤Î FAQ ¤ÇÆÀ¤ë +¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + ¤â¤· `scpx' Àܳ¥á¥½¥Ã¥É¤ò»È¤¤¤¿¤¤¤È»×¤Ã¤¿¤Ê¤é¡¢Emacs ¤¬ `c:/foo' +¤Î¤è¤¦¤Ê Windows ¥Õ¥¡¥¤¥ë̾¤òȼ¤Ê¤Ã¤Æ `scp' ¤ò¸Æ¤Ö»þ¤ËÌäÂ꤬µ¯¤­¤ë +¤«¤â¤·¤ì¤Þ¤»¤ó¡£Cygwin ÈǤΠ`scp' ¤Ï Windows ¥Õ¥¡¥¤¥ë̾¤Ë¤Ä¤¤¤ÆÃΤé +¤Ê¤¤¤Î¤Ç¡¢¤½¤ì¤ò¥Û¥¹¥È `c' ¾å¤Î¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë̾¤È²ò¼á¤·¤Æ¤·¤Þ¤¤¤Þ¤¹¡£ + + °ì¤Ä¤Î²Äǽ¤Ê²óÈòË¡¤È¤·¤Æ¤Ï¡¢Windows ¥Õ¥¡¥¤¥ë̾¤ò Cygwin +¤Î¥Õ¥¡¥¤¥ë̾¤Ë ÊÑ´¹¤¹¤ë¥é¥Ã¥Ñ¡¼¥¹¥¯¥ê¥×¥È¤ò½ñ¤¯¤³¤È¤Ç¤¹¡£ + + Ê̤βóÈòË¡¤È¤·¤Æ¤Ï Emacs ¤ò Cygwin ¾å¤Çư¤«¤¹¤«¡¢¤â¤·¤¯¤Ï Cygwin ÈǤΠ+Emacs ¤ò»È¤¦¤³¤È¤¬¤¢¤ë¤È»×¤¤¤Þ¤¹¡£ + + ²¿¤é¤«¤Î `ssh' ¤Ë´ð¤Å¤¯¥á¥½¥Ã¥É¤ò Windows ¾å¤Ç»È¤¤¤¿¤¤¾ì¹ç¡¢ +`ssh-agent' ¤Ë´Ø¤¹¤ëÌäÂê¤ËÁø¶ø¤¹¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡£¤³¤Î¥×¥í¥°¥é¥à +¤ò»È¤¦¤È¡¢¥í¥°¥¤¥ó¤ÎºÝ¤ËËè²ó¥Ñ¥¹¥Õ¥ì¡¼¥º¤òÆþÎϤ¹¤ë¤³¤È¤òÈò¤±¤ë¤³¤È¤¬ +¤Ç¤­¤Þ¤¹ (¤Þ¤¿¡¢`scpx' ¥á¥½¥Ã¥É¤Ï `ssh-agent' ¤ò»È¤¦¤³¤È¤ò +Í׵ᤷ¤Þ¤¹¡£¤Ê¤¼¤Ê¤é¤½¤ì¤Ï¥Ñ¥¹¥ï¡¼¥É¤ä¥Ñ¥¹¥Õ¥ì¡¼¥º¤òÆþÎϤµ¤»¤Æ¤¯¤ì¤Ê¤¤ +¤«¤é¤Ç¤¹)¡£¤·¤«¤·¤Ê¤¬¤é¡¢Emacs ¤ò¥Ç¥¹¥¯¥È¥Ã¥×¥·¥ç¡¼¥È¥«¥Ã¥È¤«¤éµ¯Æ°¤·¤¿ +¤Ê¤é¡¢´Ä¶­ÊÑ¿ô `SSH_AUTH_SOCK' ¤ÏÀßÄꤵ¤ì¤Ê¤¤¤Î¤Ç¡¢ Emacs ¤½¤·¤Æ +TRAMP¡¢ ¤½¤·¤Æ TRAMP ¤«¤éµ¯Æ°¤µ¤ì¤ë `ssh' ¤ª¤è¤Ó `scp' ¤Ï `ssh-agent' +¤ÈÄÌ¿®¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£Emacs ¤ò¥·¥§¥ë¤«¤éµ¯Æ° +¤¹¤ì¤Ð¤¦¤Þ¤¯Æ°¤­¤Þ¤¹¡£ + + ¤â¤·Ã¯¤« Windows +¾å¤Ç¥Ç¥¹¥¯¥È¥Ã¥×¥·¥ç¡¼¥È¥«¥Ã¥È¤¬²¸·Ã¤ò¼õ¤±¤é¤ì¤ë¤è¤¦¤Ê¡¢ `ssh-agent' +¤Îµ¯Æ°ÊýË¡¤òÃΤäƤ¤¤¿¤é¶«¤ó¤Ç²¼¤µ¤¤¡£»ä¤ÏËÜÅö¤Ë Windows +¤Ë¤Ä¤¤¤Æ¤Ï²¿¤âÃΤé¤Ê¤¤¤Î¤Ç¤¹... + + +File: tramp_ja.info, Node: Usage, Next: Bug Reports, Prev: Configuration, Up: Top + +5 TRAMP ¤Î»È¤¤Êý +**************** + +TRAMP ¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¤È¡¢TRAMP ¤Ï´°Á´¤ËÆ©²áŪ¤Ëưºî¤·¤Þ¤¹¡£ +¥í¥°¥¤¥ó²Äǽ¤Ê¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥Õ¥¡¥¤¥ë¤Ë¡¢¤¢¤¿¤«¤â¥í¡¼¥«¥ë¥Õ¥¡¥¤¥ë +¤Î¤è¤¦¤Ë¥¢¥¯¥»¥¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + TRAMP ¤Ç¤Ï¡¢formalized +¥·¥ó¥¿¥Ã¥¯¥¹¤ò»È¤¤¥Õ¥¡¥¤¥ë¤ò»ØÄꤷ¤Þ¤¹¡£¤³¤ì¤Ï¡¢ EFS +¥Ñ¥Ã¥±¡¼¥¸¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ë»÷¤Æ¤¤¤Þ¤¹¡£ + + ¤¢¤Ê¤¿¤ò¶Ã¤«¤»¤ë¤³¤È¤¬µ¯¤³¤êÆÀ¤Þ¤¹¡£ Emacs +¤ÏÁ´¤Æ¤Î¥­¡¼ÆþÎϤò²±¤¨¤Æ¤¤¤Þ¤¹¡£ ¤·¤¿¤¬¤Ã¤Æ Emacs +¤«¤é¤Î¥Ñ¥¹¥ï¡¼¥É¥×¥í¥ó¥×¥È¤òÌܤˤ·¤Æ `' +¤ò°ì²ó¤Ç¤Ê¤¯Æó²óᤤ¤¿¾ì¹ç¡¢Æó²óÌܤΥ­¡¼ÆþÎÏ¤Ï TRAMP ¤¬Æ°ºî¤·¤¿¸å¤Ç +Emacs ¤Ç½èÍý¤µ¤ì¤Þ¤¹¡£²¿¸Î¤³¤ÎÀè¹ÔÆþÎϤ¬Ä̾ï¤Îµóư¤«¤È»×¤¦¤Ç¤·¤ç¤¦¡£ +¤¢¤Ê¤¿¤ÏÀµ¤·¤¤¡¢¤·¤«¤·¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤ò³«¤¯¤Ë¤Ï¤·¤Ð¤é¤¯¤Î»þ´Ö¤¬¤«¤«¤ê¡¢ +Àܳ¤¬³«¤«¤ì¤ë¤Þ¤Ç¤Ë30É䫤«¤ë¤«¤â¤·¤ì¤Ê¤¤¤È¤¤¤¦¤³¤È¤Ëµ¤ÉÕ¤¤¤Æ²¼¤µ¤¤¡£ +¤ª¤½¤é¤¯30Éøå¤Ë¤Ï¤½¤Î¥­¡¼¤òᤤ¤¿¤³¤È¤ò¤¹¤Ç¤Ë˺¤ì¤Æ¤¤¤ë¤Ç¤·¤ç¤¦! + +* Menu: + +* Filename Syntax:: TRAMP ¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +* Multi-hop filename syntax:: ¥Þ¥ë¥Á¥Û¥Ã¥×¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +* Filename completion:: ¥Õ¥¡¥¤¥ë̾Êä´° +* Dired:: Dired + + +File: tramp_ja.info, Node: Filename Syntax, Next: Multi-hop filename syntax, Up: Usage + +5.1 TRAMP ¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +============================ + +¥ê¥â¡¼¥È¥Þ¥·¥ó MACHINE ¾å¤Î¥Õ¥¡¥¤¥ë LOCALNAME ¤Ë¥¢¥¯¥»¥¹¤¹ +¤ë¤¿¤á¤Ë¤Ï¡¢¥Õ¥¡¥¤¥ë̾ `/[MACHINE]LOCALNAME'. +¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£¤³¤ì¤Ç¡¢ MACHINE ¤ËÀܳ¤·¡¢¥Ç¥Õ¥©¥ë¥È¥á¥½¥Ã¥É +¤ò»ÈÍѤ·¤Æ¥Õ¥¡¥¤¥ë¤¬Å¾Á÷¤µ¤ì¤Þ¤¹¡£*Note Default Method::. + + TRAMP ¤Î¥Õ¥¡¥¤¥ë̾¤ÎÎã¤ò°Ê²¼¤Ëµó¤²¤Þ¤¹¡£ + +`/[melancholia].emacs' + ¥Þ¥·¥ó `melancholia' ¾å¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤¢¤ë `.emacs'¤ò + ÊÔ½¸¤·¤Þ¤¹¡£ + +`/[melancholia.danann.net].emacs' + ´°Á´¤Ê¥Û¥¹¥È̾(FQDN)¤ò»È¤¤¡¢¾å¤ÈƱ¤¸¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Þ¤¹¡£ + +`/[melancholia]~/.emacs' + ¤³¤ì¤â¤Þ¤¿Æ±¤¸¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Þ¤¹¡£`~' ¤Ï¡¢¥í¡¼¥«¥ë¤Î¾ì¹ç¤È + ƱÍͤˡ¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤ËŸ³«¤µ¤ì¤Þ¤¹¡£ + +`/[melancholia]~daniel/.emacs' + ¥Þ¥·¥ó `melancholia' ¾å¤Î¥æ¡¼¥¶¡¼ `daniel' ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê + ¤Ë¤¢¤ë¥Õ¥¡¥¤¥ë `.emacs' ¤òÊÔ½¸¤·¤Þ¤¹¡£`~<¥æ¡¼¥¶¡¼>' ¹½Ê¸¤Ï + ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥æ¡¼¥¶¡¼¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤ËŸ³«¤µ¤ì¤Þ¤¹¡£ + +`/[melancholia]/etc/squid.conf' + ¥Þ¥·¥ó `melancholia' ¾å¤Î¥Õ¥¡¥¤¥ë `/etc/squid.conf' ¤òÊÔ½¸ ¤·¤Þ¤¹¡£ + + + °ã¤¦Ì¾Á°¤ò»È¤¦¤è¤¦¤Ë»ØÄꤷ¤Ê¤¤¸Â¤ê¡¢TRAMP ¤Ï¸½ºß¤Î¥í¡¼¥«¥ë¤Ê¥æ¡¼¥¶Ì¾ +¤ò¥í¥°¥¤¥ó¤Î¤¿¤á¤Î¥ê¥â¡¼¥È¥æ¡¼¥¶¡¼Ì¾¤È¤·¤Æ»È¤¤¤Þ¤¹¡£¤â¤·¡¢°ã¤¦¥æ¡¼¥¶¡¼¤Ç +¥í¥°¥¤¥ó¤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ï¡¢¥Õ¥¡¥¤¥ë̾¤Î°ìÉô¤È¤·¤Æ¥æ¡¼¥¶¡¼Ì¾¤ò»ØÄꤹ¤ë +¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + »ØÄꤷ¤¿¥æ¡¼¥¶¡¼¤Ç¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ë¥í¥°¥¤¥ó¤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¡¢ +`/[USER@MACHINE]/PATH/TO.FILE' +¤È¤¤¤¦¥·¥ó¥¿¥Ã¥¯¥¹¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤¡£¤Ä¤Þ¤ê¡¢ `melancholia' ¤Ë¥æ¡¼¥¶¡¼ +`daniel' ¤È¤·¤ÆÀܳ¤·¤Æ¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î `.emacs' ¤òÊÔ½¸ +¤¹¤ë¾ì¹ç¡¢`/[daniel@melancholia].emacs' ¤ò»ØÄꤹ¤ì¤Ð¤è¤¤¤Î¤Ç¤¹¡£ + + ¥Õ¥¡¥¤¥ë̾¤Î°ìÉô¤È¤·¤Æ¡¢Â¾¤Î¥Õ¥¡¥¤¥ëžÁ÷¥á¥½¥Ã¥É(*note Default +Method::) ¤ò»ØÄꤹ¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£ ¤½¤¦¤¹¤ë¤Ë¤ÏºÇ½é¤Î `/[' ¤ò +`/[/' ¤ÇÃÖ¤­´¹¤¨¤Þ¤¹¡£(ËöÈø¤Î¥¹¥é¥Ã¥·¥å¤ËÃí°Õ!) +¥æ¡¼¥¶¡¼¡¢¥Þ¥·¥ó¡¢¥Õ¥¡¥¤¥ë¤Î»ØÄê¤Ïº£¤Þ¤Ç¤ÈƱ¤¸¤Ç¤¹¡£ + + ¥Þ¥·¥ó `melancholia' ¤Ë `daniel' ¤È¤·¤ÆÀܳ¤·¡¢¥Õ¥¡¥¤¥ëžÁ÷¤Ë `ssh' +¥á¥½¥Ã¥É¤ò»È¤¤¡¢¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î `.emacs' ¤òÊÔ½¸¤¹¤ë +¤¿¤á¤Ë¤Ï¡¢¥Õ¥¡¥¤¥ë̾ `/[ssh/daniel@melancholia].emacs' ¤ò»ØÄꤷ¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Multi-hop filename syntax, Next: Filename completion, Prev: Filename Syntax, Up: Usage + +5.2 ¥Þ¥ë¥Á¥Û¥Ã¥×¥Õ¥¡¥¤¥ë̾¤Î¤­¤Þ¤ê +================================== + +¥Þ¥ë¥Á¥Û¥Ã¥×¥Õ¥¡¥¤¥ë̾¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï¡¢ÅöÁ³¤Î¤³¤È¤Ê¤¬¤é¡¢Â¾¤Î TRAMP +¤Î¥Õ¥¡¥¤¥ë̾¤È¼ã´³°Û¤Ê¤ê¤Þ¤¹¡£°Ê²¼¤Ë¡¢¥Þ¥ë¥Á¥Û¥Ã¥×¥Õ¥¡¥¤¥ë̾¤ÎÎã¤ò +¤¢¤²¤Þ¤¹¡£ºÇ½é¤¬ Emacs ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ç¼¡¤¬ XEmacs ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ë¤è +¤ë¤â¤Î¤Ç¤¹: + + /[multi/rsh:out@gate/telnet:kai@real.host]/path/to.file + + ¤³¤ì¤ÏÈó¾ï¤Ë½ÅÍפʤΤǡ¢¤Ò¤È¤Ä¤Ò¤È¤ÄÀâÌÀ¤·¤Þ¤·¤ç¤¦¡£¥Õ¥¡¥¤¥ë̾¤Ï +3¤Ä¤ÎÉôʬ¤«¤éÀ®¤ê¡¢ ³ÆÉô¤Ï¥¹¥é¥Ã¥·¥å¤È³Ñ³ç¸Ì¤Ç¶èÀÚ¤é¤ì¤Þ¤¹¡£ +ºÇ½é¤Î¥Ñ¡¼¥È `/[multi' ¤Ï¥á¥½¥Ã¥É¤Î»ØÄê¤Ç¤¹¡£ ÆóÈÖÌܤΥѡ¼¥È¤Ï +`rsh:out@gate/telnet:kai@real.host' +¤Ç¥Û¥Ã¥×¤ò»ØÄꤷ¤Þ¤¹¡£ºÇ¸å¤Î¥Ñ¡¼¥È¤Ï `/path/to.file' ¤Ç¡¢¥ê¥â¡¼¥È +¥Û¥¹¥È¾å¤Î¥Õ¥¡¥¤¥ë̾¤ò»ØÄꤷ¤Þ¤¹¡£ + + ºÇ½é¤ÈºÇ¸å¤Î¥Ñ¡¼¥È¤ÏÌÀÇò¤Ç¤·¤ç¤¦¡£*Note Multi-hop Methods::¤Ë»ØÄê²Äǽ +¤Ê¥á¥½¥Ã¥É¤Î°ìÍ÷¤¬¤¢¤ê¤Þ¤¹¡£ + + ÆóÈÖÌܤΥѡ¼¥È¤Ï¡¢ºÆ¤Ó¥³¥ó¥Ý¡¼¥Í¥ó¥È¤Ë¡¢¤Ä¤Þ¤ê¥Û¥Ã¥×¤¿¤Á(hops) ¤Ëʬ³ä +¤µ¤ì¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£¾åµ­¤Î¥Õ¥¡¥¤¥ë̾¤Ë¤Ï¡¢Æó¤Ä¤Î¥Û¥Ã¥×¤¿¤Á¡¢ +`rsh:out@gate' ¤ª¤è¤Ó `telnet:kai@real.host' ¤¬´Þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£ + + ¤½¤ì¤¾¤ì¤Î¥Û¥Ã¥×¤Ï¡¢_ºÆ¤Ó_(3¤Ä¤Î)¥³¥ó¥Ý¡¼¥Í¥ó¥È¡¢ +"¥Û¥Ã¥×¥á¥½¥Ã¥É"¡¢"¥æ¡¼¥¶¡¼Ì¾"¡¢"¥Û¥¹¥È̾"¤Ëʬ³ä¤µ¤ì¤ë¤³¤È¤¬ +¤¢¤ê¤Þ¤Þ¤¹¡£ÆóÈÖÌÜ¡¢»°ÈÖÌܤΥ³¥ó¥Ý¡¼¥Í¥ó¥È¤Î°ÕÌ£¤ÏÌÀÇò¤Ç¤¹¡£¥Û¥Ã¥×¥á¥½¥Ã¥É¤Ï¡¢ +¤³¤Î¥Û¥Ã¥×¤Ç¤É¤Î¤è¤¦¤Ê¥×¥í¥°¥é¥à¤ò»È¤¦¤«¤ò°ÕÌ£¤·¤Æ¤¤¤Þ¤¹¡£ + + ºÇ½é¤Î¥Û¥Ã¥× `rsh:out@gate' ¤Ï¡¢ ¥Û¥¹¥È `gate' ¤Ë¥æ¡¼¥¶¡¼ `out' +¤È¤·¤Æ¥í¥°¥¤¥ó¤¹¤ë¤¿¤á¤Ë `rsh' ¤ò»È¤¦¤È¤¤¤¦°ÕÌ£¤Ç¤¹¡£ÆóÈÖÌÜ¤Î¥Û¥Ã¥× +`telnet:kai@real.host'`telnet:kai@real.host' ¤Ï¡¢¤³¤Î¥Û¥¹¥È¤«¤é¥Û¥¹¥È +`real.host' ¤Ë¥æ¡¼¥¶¡¼ `kai'¤Ç¥í¥° ¥¤¥ó¤¹¤ë¤¿¤á¤Ë `telnet' +¤ò»È¤¦¤È¤¤¤¦°ÕÌ£¤Ç¤¹¡£ + + *Note Multi-hop Methods::. ¤³¤³¤Ë¥Û¥Ã¥×¥á¥½¥Ã¥É¤Î°ìÍ÷¤¬¤¢¤ê¤Þ¤¹¡£ +ÊÑ¿ô `tramp-multi-connection-function-alist' ¤Ë¤Ï¡¢ÁªÂò²Äǽ¤Ê¥Û¥Ã¥× +¥á¥½¥Ã¥É¤Î¥ê¥¹¥È¤È¤½¤ì¤é¤ò¤É¤Î¤è¤¦¤Ë¼Â¹Ô¤¹¤ë¤«¤È¤¤¤¦¾ðÊó¤¬´Þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£ +¤¢¤Ê¤¿¤¬ºî¤Ã¤¿¥á¥½¥Ã¥É¤ò¤³¤ÎÊÑ¿ô¤ËÄɲ䷤Ƥ¯¤À¤µ¤¤¡£ + + +File: tramp_ja.info, Node: Filename completion, Next: Dired, Prev: Multi-hop filename syntax, Up: Usage + +5.3 ¥Õ¥¡¥¤¥ë̾Êä´° +================== + +TRAMP ¤Î¥Õ¥¡¥¤¥ë̾Êä´°¤Ï¥ê¥â¡¼¥È¥Þ¥·¥ó¤Î¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤Ë²Ã¤¨¤Æ +¥á¥½¥Ã¥É¡¢¥æ¡¼¥¶Ì¾¤ª¤è¤Ó¥Þ¥·¥ó̾(¥Þ¥ë¥Á¥Û¥Ã¥×¥á¥½¥Ã¥É¤¿¤Á¤Ï½ü¤¯)¤Ë +ÂФ·¤ÆÆ¯¤­¤Þ¤¹¡£ + + Î㤨¤Ð `C-x C-f /[t' ¤ÈÆþÎϤ¹¤ë¤È TRAMP +¤Ï°Ê²¼¤ÎÁªÂò»è¤òÊÖ¤·¤Þ¤¹¡£ + + [telnet/ [toto] + + `[telnet/' ¤Ï¥á¥½¥Ã¥É¤ÎÊä´°¤Ç¤¢¤ê¡¢ `[toto]' ¤Ï TRAMP ¤¬¥Õ¥¡¥¤¥ë +`~/.ssh/known_hosts' ¤«¤é¸¡½Ð¤·¤¿¥Û¥¹¥È̾ ¤Ç¤¹(¥Ç¥Õ¥©¥ë¥È¥á¥½¥Ã¥É `ssh' +¤ò»È¤Ã¤Æ¤¤¤ë¾ì¹ç)¡£ + + ³¤±¤Æ `e ' ¤È¤¹¤ì¤Ð¡¢¥ß¥Ë¥Ð¥Ã¥Õ¥¡¤Ï `/[telnet/' +¤ÈÊä´°¤µ¤ì¤Þ¤¹¡£¼¡¤Î `' ¤Ç¤Ï TRAMP ¤¬¥Õ¥¡¥¤¥ë `/etc/hosts' +¤«¤é¸¡½Ð¤·¤¿Á´¤Æ¤Î¥Þ¥·¥ó̾¤òµó¤²¤Þ¤¹¡£Î㤨¤Ð¡¢ + + [telnet/127.0.0.1] [telnet/192.168.0.1] + [telnet/localhost] [telnet/melancholia.danann.net] + [telnet/melancholia] + +¤³¤³¤Ç´õ˾¤Î¥Þ¥·¥ó¤òÁªÂò¤¹¤ë¤³¤È¤¬¤Ç¤­¡¢Â³¤±¤Æ¤½¤Î¥Þ¥·¥ó¾å¤Î¥Õ¥¡¥¤¥ë̾ +¤òÊä´°¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ + + ¥Õ¥¡¥¤¥ë̾Êä´°¤Ï¥ê¥â¡¼¥È¥Þ¥·¥ó¤«¤é¥Õ¥¡¥¤¥ë¥ê¥¹¥È¤ò¼è¤ê´ó¤»¤ëɬÍפ¬ +¤¢¤ë¤¿¤á¤Ë¡¢¤·¤Ð¤·¤Ð¤È¤Æ¤âÃÙ¤¯¤Ê¤ê¤Þ¤¹¡£º£¤Î½ê TRAMP ¤Ï¥Ç¥£¥ì¥¯¥È¥ê +¥ê¥¹¥È¤ò¥­¥ã¥Ã¥·¥å¤·¤Ê¤¤¤Î¤ÇÆó²óÌܤΥե¡¥¤¥ë̾Êä´°¤Ç¤â¥Ñ¥Õ¥©¡¼¥Þ¥ó¥¹ +¾å¤Î°ã¤¤¤Ï¸½¤ì¤Þ¤»¤ó¡£ + + TRAMP ¤¬Êä´°¤Î²òÀϤËÍѤ¤¤ëÀßÄê¥Õ¥¡¥¤¥ë (*note Customizing +Completion::) ¤¬¥æ¡¼¥¶Ì¾¤òÄ󶡤·¤¿¾ì¹ç¡¢¤½¤ì¤é¤Î¥æ¡¼¥¶Ì¾¤â¹Í褵¤ì¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Dired, Prev: Filename completion, Up: Usage + +5.4 Dired +========= + +TRAMP ¤Ï dired ¾å¤Ç¤âÆ©²áŪ¤Ëưºî¤·¤Þ¤¹¡£¤³¤Î¶¯ÎϤʥե¡¥¤¥ë´ÉÍý +¥Ä¡¼¥ë¤ò»È¤¤¡¢¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ò·Ðͳ¤·¥¢¥¯¥»¥¹²Äǽ¤Ê¤¹¤Ù¤Æ¤Î¥Þ¥·¥ó¾å¤Î +¥Õ¥¡¥¤¥ë¤ò´ÉÍý¤Ç¤­¤Þ¤¹¡£ + + ¥Ç¥£¥ì¥¯¥È¥ê¥Ä¥ê¡¼¤ò¥Ö¥é¥¦¥º¤·¤¿¤¤¾ì¹ç¤Ï¡¢º£¤Î¤È¤³¤í¥Õ¥¡¥¤¥ë̾¤ÎÊä´° +¤è¤ê dired ¤ò»È¤¦¤Û¤¦¤¬Îɤ¤¤Ç¤·¤ç¤¦¡£dired ¤Ï¼«¿È¤Ç¥­¥ã¥Ã¥·¥å¤Î»ÅÁÈ¤ß +¤ò¤â¤Ã¤Æ¤¤¤ë¤Î¤Ç¡¢¥Õ¥¡¥¤¥ë°ìÍ÷¤ò°ìÅÙ¤·¤«¼èÆÀ¤·¤Þ¤»¤ó¡£ + + +File: tramp_ja.info, Node: Bug Reports, Next: Frequently Asked Questions, Prev: Usage, Up: Top + +6 ¥Ð¥°¤äÌäÂê¤ÎÊó¹ð +****************** + +TRAMP ¤Î¥Ð¥°¤äÌäÂê¤Ï¡¢³«È¯¥Á¡¼¥à¤Ë¤è¤Ã¤Æ¥¢¥¯¥Æ¥£¥Ö¤Ë²ò·è¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ +»ÅÍͤ˴ؤ¹¤ë¥ê¥¯¥¨¥¹¥È¤äÄó°Æ¤â´¿·Þ¤·¤Þ¤¹¡£ + + TRAMP ¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤Ï¡¢TRAMP ¤Î¾ðÊó¤òÆþ¼ê¤·¤¿¤ê¡¢ÌäÂê¤Î²ò·è¤ä¡¢ +°ìÈÌŪ¤ÊµÄÏÀ¡¢¤½¤·¤Æ¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Ë´Ø·¸¤¹¤ëÏÃÂê¤Ø¤Î¥¢¥É¥Ð¥¤¥¹¤ËºÇŬ +¤Î¾ì½ê¤Ç¤¹¡£ + + ¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤Ï ¤Ç¤¹¡£ +¤³¤Î¥¢¥É¥ì¥¹¤Ë¥á¥Ã¥»¡¼¥¸¤ò¤òÁ÷¤ë¤È¤¹¤Ù¤Æ¤Î¹ÖÆÉ¼Ô¤ËÆÏ¤­¤Þ¤¹¡£ +¤³¤ì¤Ï¹ÖÆÉ¤Î¥ê¥¯¥¨¥¹¥È¤òÁ÷¿®¤¹¤ë¤¿¤á¤Î¥¢¥É¥ì¥¹¤Ç¤Ï _¤¢¤ê¤Þ¤»¤ó_¡£ + + ¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤ò¹ÖÆÉ¤¹¤ë¤¿¤á¤Î¥Ø¥ë¥×¤òÆþ¼ê¤¹¤ë¤Ë¤Ï¡¢¥µ¥Ö¥¸¥§¥¯¥È¤Ë +`help' ¤È½ñ¤¤¤¿¥á¡¼¥ë¤ò´ÉÍýÍѤΥ¢¥É¥ì¥¹ + ¤ËÁ÷¿®¤·¤Æ¤¯¤À¤µ¤¤¡£ + + TRAMP ¤Î¥Ð¥°Êó¹ð¤ò¤¹¤ë¾ì¹ç¤Ë¤Ï¡¢`M-x tramp-bug' ¤ò¼Â¹Ô¤·¤Æ¤¯¤À¤µ¤¤¡£ +¤³¤ì¤Ï¡¢¤¢¤Ê¤¿¤Î¥·¥¹¥Æ¥à¤Î¾ÜºÙ¤ä TRAMP ¤Î¥Ð¡¼¥¸¥ç¥ó¾ðÊó¤ò´Þ¤à¥Ð¥Ã¥Õ¥¡ +¤ò¼«Æ°Åª¤ËÀ¸À®¤·¤Þ¤¹¡£ + + ¥Ð¥°Êó¹ð¤òÄó½Ð¤¹¤ë»þ¤Ë¤Ï¡¢ÌäÂê¤òºÆ¸½¤¹¤ë¼ê½ç¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¤ÎÀßÄê¡¢ +¤â¤·Â¸ºß¤¹¤ë¤Î¤Ç¤¢¤ì¤ÐÆÃ¼ì¤Ê¾ò·ï¤ò¡¢¤·¤Ä¤³¤¤¤°¤é¤¤¾ÜºÙ¤Ëµ­½Ò¤·¤Æ¤¯ +¤À¤µ¤¤¡£¤â¤·²Äǽ¤Ê¤é¡¢´Êñ¤ÊºÆ¸½¼ê½ç¤âµ­½Ò¤·¤Æ¤¯¤À¤µ¤¤¡£ + + ¤â¤·¡¢ÌäÂê¤òºÆ¸½¤¹¤ë¤¿¤á¤Î´Êñ¤Ê¥Æ¥¹¥È¥±¡¼¥¹¤¬¤ï¤«¤ì¤Ð¡¢¤½¤ì¤ò¥Ð¥° +Êó¹ð¤Ë´Þ¤á¤Æ¤¯¤À¤µ¤¤¡£¤³¤ì¤Ë¤è¤ê¡¢³«È¯¥Á¡¼¥à¤¬¥Ð¥°¤òÆÍ¤­»ß¤á¡¢½¤Àµ +¤¹¤ë¤Î¤¬Íưפˤʤê¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Frequently Asked Questions, Next: Concept Index, Prev: Bug Reports, Up: Top + +7 ¤è¤¯¤¢¤ë¼ÁÌä¤È¤½¤ÎÅú +********************** + + * ºÇ¿·¤Î TRAMP ¤Ï¤É¤³¤«¤éÆþ¼ê¤Ç¤­¤Þ¤¹¤«? + + TRAMP ¤Ï°Ê²¼¤Î URL ¤ÇÆþ¼ê²Äǽ¤Ç¤¹ + + `http://savannah.nongnu.org/download/tramp/' + + ¤Þ¤¿ Savannah ¤Î¥×¥í¥¸¥§¥¯¥È¥Ú¡¼¥¸¤â¤¢¤ê¤Þ¤¹¡£ + + `https://savannah.gnu.org/projects/tramp/' + + * ¤É¤Î¤è¤¦¤Ê¥·¥¹¥Æ¥à¾å¤Çưºî¤·¤Þ¤¹¤«? + + ¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Ï¡¢Emacs 20 ¤È Emacs 21 ¾å¤Çưºî¤·¤Þ¤¹¡£XEmacs 20 + ¾å¤Ç¤Ï ÌäÂ꤬¤¢¤ê¤Þ¤¹¡£`tramp.el' + ¤Î¥³¥á¥ó¥È¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£Emacs 19 + ¤Ç»î¤·¤¿¿Í¤¬¤¤¤ë¤Î¤«¤É¤¦¤«¤ÏÃΤê¤Þ¤»¤ó¡£ + + ¤³¤Î¥Ñ¥Ã¥±¡¼¥¸¤Ï Unix + ¾å¤Çưºî¤¹¤ë¤è¤¦¤ËÀ߷פµ¤ì¤Æ¤¤¤Þ¤¹¡£¤½¤·¤Æ¥ê¥â¡¼¥È ¦¤â Unix + É÷¤Î¥·¥¹¥Æ¥à¤Ç¤¢¤ë¤³¤È¤ò´üÂÔ¤·¤Æ¤¤¤Þ¤¹¡£¤·¤«¤·¡¢NT Emacs ¾å¤Ç + ưºî¤µ¤»¤ë¤³¤È¤ËÀ®¸ù¤·¤¿¿Í¤¬²¿¿Í¤«¤¤¤ë¤è¤¦¤Ç¤¹¡£ + + °Ê²¼¤Î URL ¤Ë¤Ï¡¢Tramp ¤ò NT ¤Ç»È¤¦¤¿¤á¤Î¾ðÊ󤬤¢¤ê¤Þ¤¹; Joe Stoy + ¤Ë¤Ï¾ðÊó¤ÎÄ󶡤ËÂФ·¤Æ¿¼¤¯´¶¼Õ¤·¤Þ¤¹: + `ftp://ftp.comlab.ox.ac.uk/tmp/Joe.Stoy/' + + ¾åµ­¤Ï¤â¤Ã¤Ñ¤é¸Å¤¤¥Ð¡¼¥¸¥ç¥ó¤Î ssh ¤Ø¤Î¥Ñ¥Ã¥Á¤¬¤ª¤¤¤Æ¤¢¤ê¤Þ¤¹; Tom + Roche ¤Î Web page ¤Ë¤âÀâÌÀ¤¬¤¢¤ê¤Þ¤¹: + `http://www4.ncsu.edu/~tlroche/plinkTramp.html' + + ??? XEmacs ¤Î¾ðÊó¤ÏÀµ¤·¤¤¤Î¤Ç¤·¤ç¤¦¤«? + + ??? 狼¡¢NT Emacs + ¾å¤Çư¤«¤¹¤¿¤á¤Î¾ðÊó¤ò¶µ¤¨¤Æ¤¯¤À¤µ¤¤¡£¤¿¤Ö¤ó¡¢`ssh' + ´Ø·¸¤ÎÌäÂ꤬¤¢¤ë¤Î¤Ç¤Ï¤Ê¤¤¤«¤È»×¤¤¤Þ¤¹¡£ + + * XEmacs ¤Ç EFS ¤¬µ¯Æ°¤µ¤ì¤Æ¤·¤Þ¤¤¤Þ¤¹ + + ¤¹¤Ù¤Æ¤Î¸Å¤¤¥Ð¡¼¥¸¥ç¥ó¤Î TRAMP ¤¬ XEmacs XEmacs + ¤òÀµ¤·¤¯¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¤ï¤±¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£¤Þ¤ººÇ½é¤Ë¡¢ºÇ¿·¤Î + TRAMP ¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£ + + ¤â¤·ºÇ¿·¤Î¥Ð¡¼¥¸¥ç¥ó¤Ê¤é¡¢ EFS ¥Ï¥ó¥É¥é¡¼¤¬¼Â¹Ô + ¤µ¤ì¤ë¤¿¤á¤Î¾ò·ï¤òÀµ³Î¤ËÄ´¤Ù¤Æ¤¯¤À¤µ¤¤¡£¤â¤·²Äǽ¤Ê¤é¡¢¥Ö¥ì¡¼¥¯¥Ý¥¤¥ó¥È + ¤ò `efs-ftp-path' ¤ËÀßÄꤷ¤Æ¡¢¥Ð¥°Êó¹ð¤È°ì½ï¤Ë¥¹¥¿¥Ã¥¯¥È¥ì¡¼¥¹¤ò + Á÷¤Ã¤Æ¤¯¤À¤µ¤¤¡£¤³¤ì¤é¤Î¾ðÊ󤬤¢¤ë¤È¡¢³«È¯¼Ô¤¬²¿¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤Î¤«¤òȯ + ¸«¤¹¤ë¤³¤È¤¬Íưפˤʤê¤Þ¤¹¡£ + + * TRAMP ¤ò»È¤¦¤È¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤¬¤Ç¤­¤Þ¤»¤ó + + ¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ë¥í¥°¥¤¥ó¤·¤¿»þ¤Ë¡¢`ls' ¤Î½ÐÎϤ¬¿§ÉÕ¤­¤Ë¤Ê¤Ã¤Æ + ¤¤¤Þ¤»¤ó¤«? ¤â¤·¡¢¤½¤¦¤Ê¤é¡¢¤½¤ì¤¬¸¶°ø¤Ç¤¹¡£ + + `ls' ¤Ï¡¢Ã¼Ëö¥¨¥ß¥å¥ì¡¼¥¿¡¼¤¬¿§¤òÊѹ¹¤¹¤ë¤¿¤á¤Î ANSI + ¥¨¥¹¥±¡¼¥×¥·¡¼¥¯¥¨¥ó¥¹¤ò½ÐÎϤ·¤Þ¤¹¡£¤·¤«¤·¤Ê¤¬¤é¡¢¤³¤Î¥¨¥¹¥±¡¼¥× + ¥·¡¼¥¯¥¨¥ó¥¹¤Ï TRAMP ¤òº®Í𤵤»¤Þ¤¹¡£ + + ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î `.bashrc'¡¢`.profile' ¤¢¤ë¤¤¤ÏƱ¤¸¤è¤¦¤Ê + ÀßÄê¥Õ¥¡¥¤¥ë¤Ë¡¢`--color=yes' ¤Þ¤¿¤Ï `--color=auto' + ¤¬Äɲ䵤줿ÀßÄê¤Î alias ¤¬¤¢¤ë¤Ï¤º¤Ç¤¹¡£ + + ¤³¤Î alias ¤òºï½ü¤·¡¢¿·¤·¤¯¥í¥°¥¤¥ó¤·¤¿»þ¤Î `ls' ¤Î½ÐÎϤ¬ + ¿§ÉÕ¤­¤Çɽ¼¨¤µ¤ì _¤Ê¤¤_ ¤³¤È¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£¤â¤·¡¢¤³¤ì¤Ç¤â + ¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤¬Àµ¾ï¤Ëưºî¤·¤Ê¤¤¾ì¹ç¤Ï¡¢TRAMP ³«È¯¼Ô¤Ë¥Ð¥°Êó¹ð + ¤ò¤·¤Æ¤¯¤À¤µ¤¤¡£ + + * µðÂç¤Ê¥Ç¥£¥ì¥¯¥È¥ê¤ÎÃæ¤Ç¤Ï¥Õ¥¡¥¤¥ë̾¤ÎÊä´°¤¬Æ°ºî¤·¤Þ¤»¤ó + + TRAMP ¤Ï¤¤¤¯¤Ä¤«¤Î¥ª¥Ú¥ì¡¼¥·¥ç¥ó¤Ç globbing ¤ò»ÈÍѤ·¤Þ¤¹¡£(globbing + ¤È¤Ï¡¢`*.c' ¤Î¤è¤¦¤Ê¥ï¥¤¥ë¥É¥«¡¼¥ÉŸ³«¤Î¤¿¤á¤Ë¥·¥§¥ë¤ò»È¤¦¤³¤È¤Ç¤¹) + ¤³¤ì¤Ï¡¢¤¿¤¯¤µ¤ó¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤ÏŤ¤¥³¥Þ¥ó¥É¥é¥¤¥ó + ¤òºî¤ê¤Þ¤¹¡£¤¤¤¯¤Ä¤«¤Î¥·¥§¥ë¤Ç¤ÏŤ¤¥³¥Þ¥ó¥É¥é¥¤¥ó¤ò¤±¤º¤ê¤È¤Ã¤¿¤ê¡¢ + ¤¢¤ë¤¤¤Ï globbing ¼«¿È¤ò½èÍý¤Ç¤­¤Þ¤»¤ó¡£ + + ¥ê¥â¡¼¥È¥Û¥¹¥È¦¤ËµðÂç¤Ê¥Ç¥£¥ì¥¯¥È¥ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢ `ls -d * ..?* > + /dev/null' ¤Î¤è¤¦¤Ê¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤·¡¢¥Ï¥ó¥°¤¹¤ë¤« + ¤É¤¦¤«¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£Ãí°Õ¤¹¤ëɬÍפ¬¤¢¤ë¤Î¤Ï¡¢ºÇ½é¤ËÀµ¤·¤¤¥·¥§¥ë¡¢ + `/bin/sh'¡¢`ksh' ¤¢¤ë¤¤¤Ï `bash'¡¢¤Ä¤Þ¤ê tilde ¤Î + Ÿ³«¤ò¥µ¥Ý¡¼¥È¤¹¤ë¥·¥§¥ë¤«¤é»î¤¹¤Ù¤­¤À¤È¤¤¤¦»ö¤Ç¤¹¡£ + + * TRAMP ¤Ï¤É¤Î¤è¤¦¤Ê¼ïÎà¤Î¥·¥¹¥Æ¥à¤Çưºî¤·¤Þ¤¹¤« + + TRAMP ¤Ï¡¢¥ê¥â¡¼¥È¥·¥¹¥Æ¥à¤¬ Unix É÷¤Î¥·¥¹¥Æ¥à¤Ç¤¢¤ë»ö¤òÁ°Äó¤Ë¤·¤Æ + ¤¤¤Þ¤¹¡£¤Þ¤¿¡¢¥í¡¼¥«¥ë¥·¥¹¥Æ¥à¤â Unix + É÷¤Î¥·¥¹¥Æ¥à¤Î¤Û¤¦¤¬Ë¾¤Þ¤·¤¤¤Ç + ¤·¤ç¤¦¡£¤·¤«¤·¡¢¤¹¤³¤·½¤Àµ¤¹¤ì¤Ð¡¢TRAMP ¤Ï NT + ¾å¤Ç¤âưºî¤¹¤ë¤Ï¤º¤Ç¤¹¡£ + + * TRAMP + ¤Î¥Õ¥¡¥¤¥ëžÁ÷¤¬´°Î»¤·¤¿»þ¤ËÄÌÃΤµ¤»¤ë¤Ë¤Ï¤É¤¦¤¹¤ì¤Ð¤¤¤¤¤Ç¤·¤ç¤¦¤«? + + °Ê²¼¤Î¥³¡¼¥É¤ò¡¢`~/.emacs' ¤ËÄɲ䷤Ƥ¯¤À¤µ¤¤¡£¤³¤ì¤Ç¡¢¥ê¥â¡¼¥È + ¥Û¥¹¥È¤ËÂФ¹¤ëÆÉ¤ß½ñ¤­¤Î¸å¤Ë¡¢Emacs ¤¬ beep ²»¤ò¤Ê¤é¤·¤Æ¤¯¤ì¤Þ¤¹¡£ + + (defadvice tramp-handle-write-region + (after tramp-write-beep-advice activate) + " make tramp beep after writing a file." + (interactive) + (beep)) + (defadvice tramp-handle-do-copy-or-rename-file + (after tramp-copy-beep-advice activate) + " make tramp beep after copying a file." + (interactive) + (beep)) + (defadvice tramp-handle-insert-file-contents + (after tramp-copy-beep-advice activate) + " make tramp beep after copying a file." + " make tramp beep after copying a file." + (interactive) + (beep)) + + * ¥ê¥â¡¼¥È¥Û¥¹¥È¤Î `~/.sh_history' ¤È¤¤¤¦¥Õ¥¡¥¤¥ë¤¬ÈîÂ礷³¤±¤Æ¤¤¤Þ + ¤¹¡£¤³¤ì¤Ï²¿¤Ç¤¹¤«? + + TRAMP ¤Ï¥Æ¥£¥ë¥ÀŸ³«¤Î°Ù¤Ë¡¢¤·¤Ð¤·¤Ð¥ê¥â¡¼¥È¥Û¥¹¥È¤Ç `ksh' ¤ò + µ¯Æ°¤·¤Þ¤¹¡£¤¿¤Ö¤ó `ksh' ¤Ï¥Ç¥Õ¥©¥ë¥È¤ÇÍúÎò¤òÊݸ¤·¤Þ¤¹¡£TRAMP + ¤ÏÍúÎò¤ÎÊݸ¤òÄä»ß¤·¤è¤¦¤È»î¤ß¤Þ¤¹¤¬¡¢¤¢¤Ê¤¿¤¬¼ê½õ¤±¤ò¤¹¤ëɬÍפ¬¤¢¤ë + ¤«¤â¤·¤ì¤Þ¤»¤ó¡£Î㤨¤Ð¡¢¤¢¤Ê¤¿¤Î `.kshrc' ¤Ë¤³¤ì¤òÆþ¤ì¤Æ¤¯¤À¤µ¤¤: + + if [ -f $HOME/.sh_history ] ; then + /bin/rm $HOME/.sh_history + fi + if [ "${HISTFILE-unset}" != "unset" ] ; then + unset HISTFILE + fi + if [ "${HISTSIZE-unset}" != "unset" ] ; then + unset HISTSIZE + fi + + * TRAMP ¤¬ 500 ʸ»ú¤ò±Û¤¨¤ëʸ»úÎó¤òÀµ¤·¤¯Å¾Á÷¤·¤Þ¤»¤ó¡£ + + ¤¤¤¯¤Ä¤«¤Îµ©¤Ê¥·¥¹¥Æ¥à¤Ç¤Ï¡¢`process-send-string' ¤Î¼ÂÁõ¤¬ + Ť¤Ê¸»úÎó¤ËÂФ·¤Æ²õ¤ì¤Æ¤¤¤Þ¤¹¡£¤³¤Î¾ì¹ç¡¢ÊÑ¿ô `tramp-chunksize' + ¤ò 500 ¤Ë¥«¥¹¥¿¥Þ¥¤¥º¤·¤Þ¤¹¡£¤³¤ì¤¬É¬Íפ«¤É¤¦¤«¤ò¤É¤¦¤ä¤Ã¤ÆÃΤ뤫¤Ï + `tramp-chunksize' ¤ÎÀâÌÀ¤ò¸«¤Æ²¼¤µ¤¤¡£ + + + +File: tramp_ja.info, Node: Version Control, Next: Files directories and localnames, Prev: Concept Index, Up: Top + +8 ¥ê¥â¡¼¥È¥Ð¡¼¥¸¥ç¥ó¥³¥ó¥È¥í¡¼¥ë¤ÎÆâÉôưºî +****************************************** + +EFS ¤È°Û¤Ê¤ê¡¢TRAMP ¤Ï¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥·¥§¥ë¤ò¼Â¹Ô +¤·¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤Æ¡¢TRAMP ¤ò»È¤¤¥¢¥¯¥»¥¹¤·¤¿¥Õ¥¡¥¤¥ë¤Î¥Ð¡¼¥¸¥ç¥ó +´ÉÍý¤ò¤ª¤³¤Ê¤¦»ö¤¬¤Ç¤­¤Þ¤¹¡£ + +¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤ò¤ª¤³¤Ê¤¦¥Ð¥¤¥Ê¥ê¤¬¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ë¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ +¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£¤½¤·¤Æ¡¢TRAMP-REMOTE-PATH ¤Ç»ØÄꤵ¤ì¤¿ +¥Ç¥£¥ì¥¯¥È¥ê¤ËÃÖ¤«¤ì¤Æ¡¢¥¢¥¯¥»¥¹²Äǽ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡£ + + ¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤ÎÆ©²áŪ¤ÊÅý¹ç¤Ï¡¢TRAMP ¤Î¤â¤Ã¤È¤â²ÁÃͤΤ¢¤ë +µ¡Ç½¤Î¤Ò¤È¤Ä¤Ç¤¹¡£¤·¤«¤·¡¢¤Þ¤À´°Á´¤Ë¤Ï¤Û¤É±ó¤¤¾õÂ֤Ǥ¹¡£¥·¥¹¥Æ¥à¤ÎÆ©²á +À­¤ò¸þ¾å¤µ¤»¤ë¤¿¤á¤Îºî¶È¤¬Â³¤±¤é¤ì¤Æ¤¤¤Þ¤¹¡£ + +* Menu: + +* Version Controlled Files:: ¥Õ¥¡¥¤¥ë¤¬¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤ÎȽÃÇ +* Remote Commands:: ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Ç¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥³¥Þ¥ó¥É¤Î¼Â¹Ô +* Changed workfiles:: ºî¶È¥Õ¥¡¥¤¥ë¤ÎÊѹ¹¤Îȯ¸« +* Checking out files:: ºî¶È¥Õ¥¡¥¤¥ë¤Î¥ê¥Ý¥¸¥È¥ê¤«¤é¤Î¼èÆÀ +* Miscellaneous Version Control:: ¤½¤Î¾¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Ë´Ø·¸¤¹¤ë»ö + + +File: tramp_ja.info, Node: Version Controlled Files, Next: Remote Commands, Up: Version Control + +8.1 ¥Õ¥¡¥¤¥ë¤¬¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤ÎȽÃÇ +==================================================== + +VC ¥Ñ¥Ã¥±¡¼¥¸¤Ï¡¢¥Ç¥£¥¹¥¯¾å¤Î¥Þ¥¹¥¿¡¼¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò¤â¤È¤Ë¡¢»ØÄꤵ¤ì¤¿ +¥Õ¥¡¥¤¥ë¤¬¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Î´ÉÍý²¼¤Ë¤¢¤ë¤«¤É¤¦¤«¤òȽÃǤ·¤Þ¤¹¡£ +¤³¤ì¤é¤Î¥Õ¥¡¥¤¥ë¤Î¥Æ¥¹¥È¤Ï¡¢É¸½àŪ¤Ê TRAMP ¤Î»ÅÁȤߤò»È¤¤¥ê¥â¡¼¥È +¥Þ¥·¥ó¾å¤Ç¼Â¹Ô¤µ¤ì¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Remote Commands, Next: Changed workfiles, Prev: Version Controlled Files, Up: Version Control + +8.2 ¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥³¥Þ¥ó¥É¤Î¼Â¹Ô +================================================== + +¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Î¥³¥Þ¥ó¥É¤Î¼Â¹Ô¤ò²£¼è¤ê¤¹¤ë¤³¤È¤Î¤Ç¤­¤ë VC ÍѤΠ+hook ¤Ï¸ºß¤·¤Þ¤»¤ó¡£`call-process' ¤Î»ÅÁȤߤò»È¤¤¡¢ +´Ø¿ô¸Æ¤Ó½Ð¤·¤¬È¯À¸¤·¤Þ¤¹¡£´Ø¿ô¤Ï `shell-command' ¤è¤ê¡¢¼ã´³ +¸úΨŪ¤Ç¤¹¤¬¡¢¥ê¥â¡¼¥È¤Ç¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤¹¤ë¤¿¤á¤Î hook +¤ÏÍѰդµ¤ì¤Æ¤¤¤Þ¤»¤ó¡£ + + ¤È¤ê¤¢¤¨¤ºÆ°ºî¤µ¤»¤ë¤¿¤á¤Ë¡¢´Ø¿ô `vc-do-command' ¤È +`vc-simple-command' ¤Ë¡¢TRAMP ¤ò·Ðͳ¤·¥¢¥¯¥»¥¹¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ø¤Î +¥ª¥Ú¥ì¡¼¥·¥ç¥ó¤Î¤¿¤á¤Î¥ê¥¯¥¨¥¹¥È¤ò²£¼è¤¹¤ë¤³¤È¤¬ÄÌÃΤµ¤ì¤Þ¤¹¡£ + + ¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤Î¾ì¹ç¡¢¥í¡¼¥«¥ë¥Þ¥·¥ó¤ÈƱ¤¸µ¡Ç½¤òÄ󶡤¹¤ë¤¿¤á¤Ë¡¢ +`shell-command' ¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤¬¡¢¤¤¤¯¤Ä¤«¤Î¥é¥Ã¥Ñ¡¼¥³¡¼¥É¤È +¶¦¤Ë»ÈÍѤµ¤ì¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Changed workfiles, Next: Checking out files, Prev: Remote Commands, Up: Version Control + +8.3 ºî¶È¥Õ¥¡¥¤¥ë¤ÎÊѹ¹¤Îȯ¸« +============================ + +º£¤Î¤È¤³¤í¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î¥Õ¥¡¥¤¥ë¤Î mtime ¤ò¼èÆÀ¤¹¤ë°Ü¿¢À­¤Î¹â¤¤ +ÊýË¡¤Ï¸ºß¤·¤Þ¤»¤ó¡£`vc-workfile-unchanged-p' ´Ø¿ô¤Ë¡¢¥ê¥â¡¼¥È +¥Õ¥¡¥¤¥ë¤Î¤¿¤á¤Ë TRAMP ¤Î´Ø¿ô¤Î¸Æ¤Ó½Ð¤·¤¬ÄÌÃΤµ¤ì¤Þ¤¹¡£ + + `tramp-vc-workfile-unchanged-p' ´Ø¿ô¤Ï¡¢ºî¶È¥Õ¥¡¥¤¥ë¤È¥Ð¡¼¥¸¥ç¥ó +´ÉÍý¥Þ¥¹¥¿¥Õ¥¡¥¤¥ë¤ÎÊѹ¹ÅÀ¤òÄ´¤Ù¤ë¤¿¤á¤Ë VC ¤Î diff µ¡Ç½¤ò»ÈÍѤ·¤Þ¤¹¡£ + + ¤³¤ì¤ò¼Â¸½¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¥ê¥â¡¼¥È¤Ç¤Î¥·¥§¥ë¥³¥Þ¥ó¥É¤¬¼Â¹Ô²Äǽ¤Ç¤Ê¤ì¤Ð +¤Ê¤ê¤Þ¤»¤ó¡£¤³¤Î½èÍý¤Ï¡¢¥í¡¼¥«¥ë¥Õ¥¡¥¤¥ë¤Ç»È¤ï¤ì¤ë mtime ¤Î¼èÆÀ¤è¤ê +½Å¤¤½èÍý¤Ç¤¹¡£»Äǰ¤Ê¤¬¤é¡¢°Ü¿¢À­¤Î¹â¤¤²ò·èÊýË¡¤¬¸«¤Ä¤«¤ë¤Þ¤Ç¤Ï¡¢¥ê¥â¡¼¥È +¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤Î¥³¥¹¥È¤Ï¤³¤Î¤Þ¤Þ¤Ç¤·¤ç¤¦¡£ + + +File: tramp_ja.info, Node: Checking out files, Next: Miscellaneous Version Control, Prev: Changed workfiles, Up: Version Control + +8.4 ºî¶È¥Õ¥¡¥¤¥ë¤Î¥ê¥Ý¥¸¥È¥ê¤«¤é¤Î¼èÆÀ +====================================== + +¥Ç¥Õ¥©¥ë¥È¤Ç¤Ï¡¢VC +¤Ï¥ê¥â¡¼¥È¥Õ¥¡¥¤¥ë¤ò¥Á¥§¥Ã¥¯¤·¡¢¥ê¥Ý¥¸¥È¥ê¤«¤é¥Á¥§¥Ã¥¯ +¥¢¥¦¥È¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤¬¤¢¤ë¾ì¹ç¤Ï¡¢¥Á¥§¥Ã¥¯¥¢¥¦¥È¤ò¤ª¤³¤Ê¤¤¤Þ¤»¤ó¡£¤³¤ÎÌäÂê +¤ò²ò·è¤¹¤ë¤¿¤á¤Ë¡¢´Ø¿ô `vc-checkout' ¤Ï TRAMP ¥Õ¥¡¥¤¥ë¤ò¶èÊ̤·¡¢ +¥Ð¡¼¥¸¥ç¥ó´ÉÍý¤ò¤ª¤³¤Ê¤¦¤³¤È¤ò²Äǽ¤Ë¤·¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Miscellaneous Version Control, Prev: Checking out files, Up: Version Control + +8.5 ¤½¤Î¾¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Ë´Ø·¸¤¹¤ë»ö +============================================ + +¤³¤Þ¤«¤Ê¼ÂÁõ¤Î¾ÜºÙ¡¢¤½¤Î¾¡£ + +* Menu: + +* Remote File Ownership:: VC ¤¬¥ï¡¼¥¯¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥Ê¡¼¤òÄ´¤Ù¤ëÊýË¡ +* Back-end Versions:: VC ¤¬ RCS ¤Î¥Ð¡¼¥¸¥ç¥ó¤òÄ´¤Ù¤ëÊýË¡ + + +File: tramp_ja.info, Node: Remote File Ownership, Next: Back-end Versions, Up: Miscellaneous Version Control + +8.5.1 VC ¤¬¥ï¡¼¥¯¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥Ê¡¼¤òÄ´¤Ù¤ëÊýË¡ +----------------------------------------------- + +Emacs ¤Ï¡¢Ç¤°Õ¤Î¥æ¡¼¥¶¡¼ ID ¤ÎÃÍ¤È¥í¥°¥¤¥ó̾¤ò¥Þ¥Ã¥Ô¥ó¥°¤¹¤ë¤Î¤ÈƱÍͤˡ¢ +¸½ºß¤Î¥æ¡¼¥¶¡¼¤Î¥í¥°¥¤¥ó̾¤ò¤«¤¨¤¹´Ø¿ô `user-full-name' ¤òÍѰդ·¤Æ +¤¤¤Þ¤¹¡£VC ¤Ï¡¢¤¤¤¯¤Ä¤«¤Î¾õ¶·¤Ç¡¢¥ï¡¼¥¯¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥Ê¡¼¤Î uid ¤«¤é¥í¥° +¥¤¥ó̾¤Ø¤Î¥Þ¥Ã¥×µ¡Ç½¤ò»ÈÍѤ·¤Þ¤¹¡£ + +¤³¤ì¤Ï¡¢¥ê¥â¡¼¥È¥·¥¹¥Æ¥à¤¬°Û¤Ê¤ë¥í¥°¥¤¥ó¥»¥Ã¥È¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤¢¤­¤é¤« +¤ËÀµ¤·¤¯Æ°ºî¤·¤Þ¤»¤ó¡£¤·¤¿¤¬¤Ã¤Æ¡¢uid +¤ËÂбþ¤¹¤ë¥í¥°¥¤¥ó̾¤Î·èÄê¤ò¥ê¥â¡¼¥È +¥Þ¥·¥ó¤Ë¤ª¤³¤Ê¤ï¤»¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£ + + »Äǰ¤Ê¤¬¤é¡¢`NIS'¡¢`NIS+'¤½¤·¤Æ `NetInfo' ¤Î¤è¤¦¤Ê¡¢ +ʬ»¶´ÉÍý¥·¥¹¥Æ¥à ¤ò»È¤¦¾ì¹ç¡¢¥·¥ó¥×¥ë¤Ç¡¢¿®ÍêÀ­¤¬¤¢¤ê¡¢°Ü¿¢À­¤Î¹â¤¤ +¥Þ¥Ã¥Ô¥ó¥°¤ÎÊýË¡¤Ï¸ºß¤·¤Þ¤»¤ó¡£ + + ¤¢¤ê¤¬¤¿¤¤»ö¤Ë¡¢uid ¤«¤é¥í¥°¥¤¥ó̾¤Ø¤Î¥Þ¥Ã¥Ô¥ó¥°¤Ë°Í¸¤¹¤ë VC +¤Î¥³¡¼¥É¤Ï¡¢ ´Ø¿ô `vc-file-owner' +¤Ò¤È¤Ä¤À¤±¤Ç¤¹¡£¤³¤Î´Ø¿ô¤Ï¡¢¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥Ê¡¼ +¤Î¥í¥°¥¤¥ó̾¤òʸ»úÎó¤È¤·¤ÆÊÖ¤·¤Þ¤¹¡£ + + ¥í¥°¥¤¥ó̾¤ò·èÄꤹ¤ë¤¿¤á¤Ë¡¢¤³¤Î´Ø¿ô¤Ë¡¢¥ê¥â¡¼¥È¥Þ¥·¥ó¾å¤Î `ls' +¤Î½ÐÎϤò»ÈÍѤ¹¤ë¤³¤È¤¬ÄÌÃΤµ¤ì¤Þ¤¹¡£uid ¤«¤é¥í¥°¥¤¥ó̾¤Î¥Þ¥Ã¥Ô¥ó¥°¤ò¡¢ +»ä¤è¤ê¤½¤ì¤é¤Ë¤Ä¤¤¤ÆÎɤ¯ÃΤäƤ¤¤ë¤Ï¤º¤Î¥ê¥â¡¼¥È¥·¥¹¥Æ¥à¤Ë°Ñ¾ù¤·¤Þ¤¹¡£ + + +File: tramp_ja.info, Node: Back-end Versions, Prev: Remote File Ownership, Up: Miscellaneous Version Control + +8.5.2 VC ¤¬ RCS ¤Î¥Ð¡¼¥¸¥ç¥ó¤òÄ´¤Ù¤ëÊýË¡ +---------------------------------------- + +VC ¤Ï¡¢¤É¤Î¥ê¥ê¡¼¥¹¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Î¥Ð¥¤¥Ê¥ê¤ò»È¤Ã¤Æ¤¤¤ë¤«¤ò +ÃΤëɬÍפ¬¤¢¤ê¤Þ¤¹¡£¤³¤ì¤Ï¡¢VC ¤¬¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¤¹¤Ù¤Æ¤Îµ¡Ç½¤ò¡¢¸Å¤¤ +¥Ð¡¼¥¸¥ç¥ó¤Î`rcs(1)'¡¢`cvs(1)'¡¢`sccs(1)'¤¬Äó¶¡ +¤·¤Æ¤¤¤ë¤ï¤±¤Ç¤Ï̵¤¤¤«¤é¤Ç¤¹¡£ + + VC +¤Î¥Ç¥Õ¥©¥ë¥È¤Î¼ÂÁõ¤Ç¤Ï¡¢ºÇ½é¤ËɬÍפˤʤä¿»þ¤Ë¡¢¤³¤ÎÃͤò·èÄꤷ¤Þ¤¹¡£ +¤³¤ì¤Ï¡¢É¬Íפˤʤä¿»þ¤ËËè²ó¥×¥í¥»¥¹¤ò¼Â¹Ô¤·¡¢¤½¤Î½ÐÎϤò¥Ñ¡¼¥¹¤¹¤ë¤³¤È¤Î +¥ª¡¼¥Ð¡¼¥Ø¥Ã¥É¤ò¤µ¤±¤ë¤¿¤á¤Ç¤¹¡£ + + ¤¤¤«¤·¡¢¥ê¥â¡¼¥È¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥·¥¹¥Æ¥à¤Î»ö¤¬´Ø·¸¤·¤Æ¤¯¤ë¤È¡¢¿ÍÀ¸¤Ï +¤½¤ì¤Û¤É´Êñ¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£¥ê¥â¡¼¥È¥Þ¥·¥ó¤Ï¤½¤ì¤¾¤ì¡¢°Û¤Ê¤ë¥Ð¡¼¥¸¥ç¥ó +¤Î¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥Ä¡¼¥ë¤ò¤â¤Ã¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤¬º¤Æñ¤Ê´Ö¤Ï¡¢Â¸ºß¤·¤Ê¤¤µ¡Ç½ +¤¬¡¢¥ê¥â¡¼¥È¤Ç»ÈÍѤµ¤ì¤Ê¤¤¤³¤È¤òÊݾڤ¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£ + + ¤³¤ÎÌäÂê¤ò²ò·è¤¹¤ë¤¿¤á¤Ë¡¢¸½ºß¤Î TRAMP ¤Ï¡¢¥Ð¡¼¥¸¥ç¥ó´ÉÍý¥Ä¡¼¥ë¤Î +¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤ò TRAMP ¥Ð¥Ã¥Õ¥¡Ëè¤Ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ë¤·¡¢¿·¤·¤¤ +¥Õ¥¡¥¤¥ë¤ò³«¤¯¤¿¤Ó¤ËVC ¤Ë¤³¤ÎÃͤò·èÄꤵ¤»¤ë¤È¤¤¤¦ÎϤº¤¯¤Î¥¢¥×¥í¡¼¥Á +¤òºÎÍѤ·¤Æ¤¤¤Þ¤¹¡£ + + ¤³¤ì¤Ï¤¢¤­¤é¤«¤ËÀ­Ç½¤Ë±Æ¶Á¤·¤Þ¤¹¡£¤¢¤ê¤¬¤¿¤¤¤³¤È¤Ë¡¢VC +¤Ë¤è¤Ã¤Æ¤ª¤³¤Ê¤ï¤ì¤ë +¤Û¤È¤ó¤É¤Î½èÍý¤Ï¡¢¼ÂºÝ¤Ë¤Ï¥ê¥â¡¼¥È¤Î¥Ð¡¼¥¸¥ç¥ó¤òÃΤ뤳¤È¤òɬÍפȤ·¤Þ¤»¤ó¡£ +¤·¤¿¤¬¤Ã¤Æ¡¢¤½¤ì¤Û¤ÉÌäÂê¤Ë¤Ê¤ê¤Þ¤»¤ó¡£ + + ºÇ½ªÅª¤Ë¤Ï¡¢¤³¤ì¤é¤ÎÊÑ¿ô¤Ï TRAMP ¤Ë¤è¤Ã¤Æ¥·¥¹¥Æ¥àËè¤ËÄ´¤Ù¤é¤ì¡¢ +¤½¤Î·ë²Ì¤ÏÀ­Ç½¤ò²þÁ±¤¹¤ë¤¿¤á¤Ë¥­¥ã¥Ã¥·¥å¤µ¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¤Ç¤·¤ç¤¦¡£ + + +File: tramp_ja.info, Node: Files directories and localnames, Next: Issues, Prev: Version Control, Up: Top + +9 ¥Õ¥¡¥¤¥ë̾¡¢¥Ç¥£¥ì¥¯¥È¥ê¡¢¥í¡¼¥«¥ë̾¤¬¤É¤Î¤è¤¦¤ËÊÑ´¹¤µ¤ì(mangled)¡¢´ÉÍý¤µ¤ì¤ë¤« +********************************************************************************* + +* Menu: + +* Localname deconstruction:: ¥í¡¼¥«¥ë̾¤Îʬ²ò + + +File: tramp_ja.info, Node: Localname deconstruction, Up: Files directories and localnames + +9.1 ¥í¡¼¥«¥ë̾¤Îʬ²ò +==================== + +TRAMP ¤Î¥Õ¥¡¥¤¥ë̾¤ÏÉáÄ̤Υե¡¥¤¥ë̾¤È¤ÏÌÀ¤é¤«¤Ë°Û¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£ +¤·¤¿¤¬¤Ã¤Æ¡¢lisp ¤Î´Ø¿ô `file-name-directory' ¤È +`file-name-nondirectory' ¤Ï¡¢TRAMP ¥Ñ¥Ã¥±¡¼¥¸Æâ¤Ç¾å½ñ¤­¤µ¤ì¤Æ ¤¤¤Þ¤¹¡£ + + ´Ø¿ô¤ÎÃÖ¤­´¹¤¨¤Ï¥·¥ó¥×¥ë¤«¤ÄŬÀÚ¤ÊÊýË¡¤Ç¤¹¡£¥Õ¥¡¥¤¥ë̾¤òʬ²ò¤·¡¢ +¥í¡¼¥«¥ë̾¤ËÂФ·¤Æ¥ª¥ê¥¸¥Ê¥ë¤Î¥Ï¥ó¥É¥é¡¼¤¬¤è¤Ð¤ì¤Þ¤¹¡£¤½¤·¤Æ¡¢ +¤½¤Î·ë²Ì¤ò¤â¤È¤Ë TRAMP ¥Õ¥¡¥¤¥ë̾¤¬ºÆ¹½À®¤µ¤ì¤Þ¤¹¡£ + + ¤³¤ì¤Ë¤è¤ê¡¢TRAMP ¥Õ¥¡¥¤¥ë̾¤Î¾ðÊó¤ò°·¤¦¾ì¹ç¤â¡¢¥×¥é¥Ã¥È¥Û¡¼¥à¸ÇÍ­¤Î +¥ª¥ê¥¸¥Ê¥ë¥Ï¥ó¥É¥é¡¼¤Î¥Ï¥Ã¥¯¤ÏÍ­¸ú¤Ç¤¹¡£ + + +File: tramp_ja.info, Node: Issues, Prev: Files directories and localnames, Up: Top + +10 ¸¡Æ¤²ÝÂê¤È·èÄê»ö¹à +********************* + + * uuencode ¥á¥½¥Ã¥É¤¬¤¤¤Ä¤âưºî¤¹¤ë¤ï¤±¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó + + TRAMP ¤ÎÀß·×¾å¤ÎÍýͳ¤Ç¡¢É乿²½¤ÈÉü¹æ²½¤ò¤ª¤³¤Ê¤¦¥×¥í¥°¥é¥à¤Ïɸ½à + ÆþÎϤ«¤éÆÉ¤ß¹þ¤ß¡¢É¸½à½ÐÎϤ˽ñ¤­¹þ¤àɬÍפ¬¤¢¤ê¤Þ¤¹¡£¤¤¤¯¤Ä¤«¤Î¥·¥¹¥Æ¥à + ¤Ç¤Ï¡¢`uudecode -o -' ¤Çɸ½àÆþÎϤ«¤éÆÉ¤ß¹þ¤ß¡¢Éü¹æ²½¤µ¤ì¤¿¥Õ¥¡¥¤¥ë + ¤òɸ½à½ÐÎϤ˽ñ¤­¹þ¤ß¤Þ¤¹¡£Â¾¤Î¥·¥¹¥Æ¥à¤Ç¤Ï¡¢`uudecode -p' ¤¬Æ±¤¸ + ưºî¤ò¤·¤Þ¤¹¡£¤·¤«¤·¡¢¤¤¤¯¤Ä¤«¤Î¥·¥¹¥Æ¥à¤Î uudecode + ¤Î¼ÂÁõ¤Ç¤Ï¡¢¤³¤ì¤é ¤Î¤³¤È¤¬Á´¤¯¤Ç¤­¤Þ¤»¤ó¡£¤³¤ì¤é¤Î uudecode + ¤Î¼ÂÁõ¤Ë¡¢É¸½à½ÐÎϤ˽ñ¤­¹þ¤à + ¤¿¤á¤ËŬÀڤʥѥé¥á¡¼¥¿¤òÅϤ·¤Æ¸Æ¤Ö¤³¤È¤ÏÉÔ²Äǽ¤Ç¤¹¡£ + + ¤â¤Á¤í¤ó¡¢¤³¤ì¤ò²óÈò¤¹¤ë»ö¤Ï²Äǽ¤Ç¤¹¡£¥Æ¥ó¥Ý¥é¥ê¥Õ¥¡¥¤¥ë̾¤òÄɲ乤ë + ¤¿¤á¤Ë `begin foo 644' ¹Ô¤ò½ñ¤­¤«¤¨¤ì¤Ð¡¢`uudecode' ¤ò¸Æ¤Ö¤³¤È + ¤¬¤Ç¤­¤Þ¤¹¡£¤½¤·¤Æ¥Æ¥ó¥Ý¥é¥ê¥Õ¥¡¥¤¥ë¤òɽ¼¨¤·ºï½ü¤·¤Þ¤¹¡£ + + ¤·¤«¤·¡¢¤³¤ÎÊýË¡¤Ï¤¢¤Þ¤ê¤Ë¤â¿®ÍêÀ­¤¬Ä㤤¤¿¤á¡¢¤¤¤¯¤Ä¤«¤Î¥·¥¹¥Æ¥à¤Ç¤Ï + uuencode ¥á¥½¥Ã¥É¤ò»ÈÍѤǤ­¤Ê¤¤¤Þ¤Þ¤Ë¤·¤Æ¤ª¤¯»ö¤Ë¤·¤Þ¤·¤¿¡£ + + * TRAMP ¤Ï XEmacs 20 ¾å¤Çư¤­¤Þ¤»¤ó + + ¤³¤ì¤Ï¡¢XEmacs 20 ¤Ë¸ºß¤·¤Ê¤¤¥Þ¥¯¥í `with-timeout' ¤ò»È¤Ã¤Æ¤¤¤ë + ¤«¤é¤Ç¤¹¡£»ä¤Ï¡¢¥¨¥ß¥å¥ì¡¼¥·¥ç¥ó¤Î¤¿¤á¤Î¥Þ¥¯¥í¤ò TRAMP ¤ËÄɲ乤ë + ¤³¤È¤Ë¡¢¤¢¤Þ¤ê¾è¤êµ¤¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£¤·¤«¤·¡¢XEmacs 20 + ¥æ¡¼¥¶¡¼¤Î狼¤¬ + ÀѶËŪ¤Ë¼ÂÁõ¤È¥Æ¥¹¥È¤ò¤·¤¿¤¤¤È¹Í¤¨¤Æ¤¤¤ë¤Î¤Ç¤¢¤ì¤Ð¡¢»ä¤«¥á¡¼¥ê¥ó¥°¥ê¥¹¥È + ¤ËÏ¢Íí¤·¤Æ¤¯¤À¤µ¤¤¡£ + + * TRAMP ¥Õ¥¡¥¤¥ë̾¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤¬ Emacs ¤È XEmacs ¤Ç°ã¤¤¤Þ¤¹¡£ + + Emacs + ¤Î¥á¥ó¥Æ¥Êã¤Ï¡¢¥æ¡¼¥¶¤¬¿·¤·¤¤¥·¥ó¥¿¥Ã¥¯¥¹¤òÊÙ¶¯¤¹¤ëɬÍפ¬¤Ê¤¤¤è + ¤¦¤Ë Ange-FTP ¤È TRAMP ¤ÇÅý°ì¤µ¤ì¤¿¥Õ¥¡¥¤¥ë̾¥·¥ó¥¿¥Ã¥¯¥¹¤ò»È¤¤¤¿¤¤ + ¤È˾¤ó¤Ç¤¤¤Þ¤¹¡£ + + XEmacs + ¤Î¥á¥ó¥Æ¥Ê¤Ë¤È¤Ã¤Æ¤Ï¡¢Åý°ì¤µ¤ì¤¿¥Õ¥¡¥¤¥ë̾¥·¥ó¥¿¥Ã¥¯¥¹¤òÍѤ¤¤ë + ¤³¤È¤Ë¤è¤ëÍø±×¤è¤ê¤â¤½¤Î¤³¤È¤Ë¤è¤ëÌäÂê¤ÎÊý¤¬Â礭¤¤¤Ç¤¹¡£ XEmacs + ¤Î¥Ñ¥Ã¥±¡¼¥¸¥·¥¹¥Æ¥à¤Ï¥Ñ¥Ã¥±¡¼¥¸¤ò¥À¥¦¥ó¥í¡¼¥É¤¹¤ë¤Î¤Ë EFS ¤ò + »È¤¤¤Þ¤¹¡£¤·¤¿¤¬¤Ã¤ÆÌÀ¤é¤«¤Ë EFS + ¤ÏºÇ½é¤«¤é¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤Ï¤º + ¤Ç¤¹¡£¤â¤·¥Õ¥¡¥¤¥ë̾¤¬Åý°ì¤µ¤ì¤Æ¤¤¤¿¤È¤¹¤ë¤È¡¢TRAMP ¤â¤Þ¤¿ºÇ½é¤«¤é + ¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£ + + + +File: tramp_ja.info, Node: Concept Index, Next: Version Control, Prev: Frequently Asked Questions, Up: Top + +Concept Index +************* + +[index] +* Menu: + +* .login file: Remote shell setup. (line 6) +* .profile file: Remote shell setup. (line 6) +* auto-save: Auto-save and Backup. + (line 6) +* backup: Auto-save and Backup. + (line 6) +* base-64 encoding: Inline methods. (line 17) +* behind the scenes: Overview. (line 57) +* bug reports: Bug Reports. (line 6) +* choosing the right method: Default Method. (line 52) +* configuration: Configuration. (line 6) +* connection types, overview: Connection types. (line 6) +* create your own methods: Customizing Methods. (line 6) +* customizing completion: Customizing Completion. + (line 6) +* customizing methods: Customizing Methods. (line 6) +* Cygwin (with scpx method): External transfer methods. + (line 74) +* Cygwin (with sshx method): Inline methods. (line 76) +* Cygwin and ssh-agent: Windows setup hints. (line 26) +* Cygwin, issues: Windows setup hints. (line 6) +* default configuration: Configuration. (line 6) +* default method: Default Method. (line 6) +* details of operation: Overview. (line 57) +* development history: History. (line 6) +* dired: Dired. (line 6) +* external methods: Connection types. (line 15) +* external transfer methods <1>: External transfer methods. + (line 6) +* external transfer methods: Connection types. (line 15) +* FAQ: Frequently Asked Questions. + (line 6) +* fcp (with fcp method): External transfer methods. + (line 100) +* fcp method: External transfer methods. + (line 100) +* filename completion: Filename completion. (line 6) +* filename examples: Filename Syntax. (line 6) +* filename syntax: Filename Syntax. (line 6) +* filename syntax for multi-hop files: Multi-hop filename syntax. + (line 6) +* frequently asked questions: Frequently Asked Questions. + (line 6) +* fsh (with fcp method): External transfer methods. + (line 100) +* fsh method: External transfer methods. + (line 113) +* history: History. (line 6) +* hop method rsh: Multi-hop Methods. (line 25) +* hop method ssh: Multi-hop Methods. (line 32) +* hop method su: Multi-hop Methods. (line 36) +* hop method sudo: Multi-hop Methods. (line 50) +* hop method telnet: Multi-hop Methods. (line 21) +* how it works: Overview. (line 57) +* inline methods <1>: Inline methods. (line 6) +* inline methods: Connection types. (line 15) +* Kerberos (with krlogin method): Inline methods. (line 102) +* km krlogin: Inline methods. (line 102) +* method fcp: External transfer methods. + (line 100) +* method fsh: External transfer methods. + (line 113) +* method krlogin: Inline methods. (line 102) +* method multi: Multi-hop Methods. (line 13) +* method plink: Inline methods. (line 106) +* method pscp: External transfer methods. + (line 92) +* method rcp: External transfer methods. + (line 26) +* method rsh: Inline methods. (line 28) +* method rsync: External transfer methods. + (line 60) +* method scp: External transfer methods. + (line 34) +* method scpx: External transfer methods. + (line 74) +* method scpx with Cygwin: Windows setup hints. (line 15) +* method smb: External transfer methods. + (line 119) +* method ssh: Inline methods. (line 36) +* method sshx: Inline methods. (line 76) +* method sshx with Cygwin: Windows setup hints. (line 8) +* method su: Inline methods. (line 62) +* method sudo: Inline methods. (line 67) +* method telnet: Inline methods. (line 58) +* methods, external transfer <1>: External transfer methods. + (line 6) +* methods, external transfer: Connection types. (line 15) +* methods, inline <1>: Inline methods. (line 6) +* methods, inline: Connection types. (line 15) +* methods, multi-hop <1>: Multi-hop Methods. (line 6) +* methods, multi-hop: Connection types. (line 36) +* methods, out-of-band <1>: External transfer methods. + (line 6) +* methods, out-of-band: Connection types. (line 15) +* mimencode: Inline methods. (line 17) +* multi method: Multi-hop Methods. (line 13) +* multi-hop filename syntax: Multi-hop filename syntax. + (line 6) +* multi-hop methods <1>: Multi-hop Methods. (line 6) +* multi-hop methods: Connection types. (line 36) +* obtaining Tramp: Obtaining Tramp. (line 6) +* out-of-band methods <1>: External transfer methods. + (line 6) +* out-of-band methods: Connection types. (line 15) +* overview: Overview. (line 6) +* plink (with pscp method): External transfer methods. + (line 92) +* plink method: Inline methods. (line 106) +* pscp (with pscp method): External transfer methods. + (line 92) +* pscp method: External transfer methods. + (line 92) +* PuTTY (with pscp method): External transfer methods. + (line 92) +* rcp (with rcp method): External transfer methods. + (line 26) +* rcp method: External transfer methods. + (line 26) +* remote shell setup: Remote shell setup. (line 6) +* rsh (with rcp method): External transfer methods. + (line 26) +* rsh hop method: Multi-hop Methods. (line 25) +* rsh method: Inline methods. (line 28) +* rsync (with rsync method): External transfer methods. + (line 60) +* rsync method: External transfer methods. + (line 60) +* scp (with scp method): External transfer methods. + (line 34) +* scp (with scpx method): External transfer methods. + (line 74) +* scp method: External transfer methods. + (line 34) +* scpx method: External transfer methods. + (line 74) +* scpx method with Cygwin: Windows setup hints. (line 15) +* selecting config files: Customizing Completion. + (line 6) +* shell init files: Remote shell setup. (line 6) +* smb method: External transfer methods. + (line 119) +* ssh (with rsync method): External transfer methods. + (line 60) +* ssh (with scp method): External transfer methods. + (line 34) +* ssh (with scpx method): External transfer methods. + (line 74) +* ssh hop method: Multi-hop Methods. (line 32) +* ssh method: Inline methods. (line 36) +* ssh-agent: External transfer methods. + (line 16) +* SSH_AUTH_SOCK and Emacs on Windows: Windows setup hints. (line 26) +* sshx method: Inline methods. (line 76) +* sshx method with Cygwin: Windows setup hints. (line 8) +* su hop method: Multi-hop Methods. (line 36) +* su method: Inline methods. (line 62) +* sudo hop method: Multi-hop Methods. (line 50) +* sudo method: Inline methods. (line 67) +* telnet hop method: Multi-hop Methods. (line 21) +* telnet method: Inline methods. (line 58) +* tset Unix command: Remote shell setup. (line 61) +* type-ahead: Usage. (line 14) +* Unix command tset: Remote shell setup. (line 61) +* using non-standard methods: Customizing Methods. (line 6) +* using TRAMP: Usage. (line 6) +* uuencode: Inline methods. (line 17) +* Version Control: Version Control. (line 6) + + + +Tag Table: +Node: Top1393 +Node: Overview5861 +Ref: Overview-Footnote-112232 +Node: Obtaining Tramp12421 +Node: History14132 +Node: Configuration14871 +Node: Connection types16670 +Node: Inline methods18551 +Node: External transfer methods23623 +Ref: External transfer methods-Footnote-130989 +Node: Multi-hop Methods31060 +Node: Default Method33932 +Node: Customizing Methods38076 +Node: Customizing Completion38523 +Node: Remote Programs41364 +Node: Remote shell setup42899 +Node: Auto-save and Backup49295 +Node: Windows setup hints50495 +Node: Usage52327 +Node: Filename Syntax53444 +Node: Multi-hop filename syntax55546 +Node: Filename completion57460 +Node: Dired58795 +Node: Bug Reports59250 +Node: Frequently Asked Questions60564 +Node: Version Control66066 +Node: Version Controlled Files67174 +Node: Remote Commands67616 +Node: Changed workfiles68446 +Node: Checking out files69214 +Node: Miscellaneous Version Control69689 +Node: Remote File Ownership70071 +Node: Back-end Versions71268 +Node: Files directories and localnames72688 +Node: Localname deconstruction73030 +Node: Issues73652 +Node: Concept Index75719 + +End Tag Table diff --git a/xemacs-packages/lisp/bbdb/ChangeLog b/xemacs-packages/lisp/bbdb/ChangeLog new file mode 100644 index 00000000..f88a5a8e --- /dev/null +++ b/xemacs-packages/lisp/bbdb/ChangeLog @@ -0,0 +1,1140 @@ +2005-10-12 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.29 released. + +2005-07-27 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.28 released. + +2005-07-24 Waider + * Sync to SourceForge CVS + +2005-07-24 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.27 released. + +2005-05-10 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.26 released. + +2004-11-08 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.25 released. + +2004-09-29 Steve Youngs + + * Makefile (REQUIRES): Add ecrypto. + +2003-10-31 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.24 released. + +2003-05-18 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.23 released. + +2003-05-14 Vin Shelton + + * Makefile (REQUIRES): Added os-utils to find jka-compr, necessary + to compile mhe. + +2003-05-14 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.22 released. + +2003-05-14 Steve Youngs + + * Makefile (REQUIRES): Add net-utils. + +2003-03-09 Ben Wing + + * Makefile (DOCS_TEXINFO_EXTENSION): New. + Delete explicit compile:: and binkit: rules. + Don't add custom-load.elc to the list of generated elc's. + Use EXPLICIT_DOCS instead of explicitly giving the targets + and dependencies. + Eliminate the recursive building of the files using Makefile + (now deleted) in subdirectory texinfo/. + Use DOCS_TEXINFO_EXTENSION, since the docs are named .texinfo + rather than .texi. + * texi/Makefile: Delete. + +2002-11-29 Ben Wing + + * .cvsignore: Remove files now handled automatically by CVS. + * lisp/.cvsignore: Ditto. + * Makefile: Use `compile' instead of hard-coded `all'. + * texinfo/Makefile: Use `compile' instead of hard-coded `all'. + +2002-10-15 Ville Skyttä + + * Makefile (srckit): Remove. + (.PHONY): Ditto. + +2002-10-14 Ville Skyttä + + * Makefile (MANUAL): Removed (unused). + +2002-10-13 Ville Skyttä + + * Makefile (REQUIRES): Add indirect fsf-compat, eterm, and + sh-script requirements. + (PRELOADS): New, preload vm-version. + +2002-07-15 Adrian Aichner + + * lisp/bbdb-xemacs.el: It's XEmacs, not Xemacs. + +2002-06-27 Steve Youngs + + * Makefile (VERSION): XEmacs package 1.21 released. + +2002-06-12 Steve Youngs + + * lisp/bbdb-vm.el (bbdb/vm-set-auto-folder-alist): Typo fix. + +2002-03-25 Steve Youngs + + * Makefile (VERSION): 1.20 released. + +2002-03-17 Adrian Aichner + + * texinfo/Makefile: include .../XEmacs.rules for generic HTML + rules. + * texinfo/Makefile (HTML_FILES): Moved here from ../Makefile. + * texinfo/Makefile (HTML_DEP): Ditto. + * texinfo/Makefile (all): Converted to double-colon + * texinfo/Makefile (clean): Ditto. + +2002-03-17 Adrian Aichner + + * Makefile: Add html rule to invoke texinfo/Makefile. + +2002-03-12 Adrian Aichner + + * texinfo/bbdb.texinfo: Fix typos found + by my own grep-for-likely-typo.pl. + +2002-02-21 Nix + + * lisp/bbdb-com.el (top-level): Evaluate fsets at runtime, + as well as at compilation time. + +2002-02-13 Steve Youngs + + * Sync to BBDB 2.34. + + * lisp/bbdb-sc.el (bbdb-insinuate-sc): Autoload it. + +2002-01-15 Waider + + * testing/bbdb-test.el: + New file + + * bits/make.bat: + Merged in some changes from the mailing list. Note, this is + still experimental. + + * lisp/bbdb-com.el: + Don't fset things that aren't ours + Last of compiler warning cleanup + Fixed one more completion bug + +2002-01-14 Waider + + * lisp/bbdb-hooks.el: + Conditionalise the rmail load + + * lisp/bbdb-gui.el: + Make X/Emacs compatibility less intrusive + +2002-01-13 Waider + + * lisp/bbdb-hooks.el: + Don't force VM on people, even if it is a great mailer... + +2002-01-10 Waider + + * bbdb-com.el: + Last few fixes (hopefully) to completion + + * lisp/bbdb-snarf.el: + Make bbdb-rfc822-addresses the default address parser + Remove test-harness code to elsewhere (i.e. not in user code!) + + * lisp/bbdb.el: + Changed the workaround for set-keymap-prompt, as it seemed to be + clashing with VM. Ideally, all this Emacs/XEmacs stuff should go + in a separate file, or at least all in one part of bbdb.el. + +2002-01-06 Waider + + * lisp/bbdb-xemacs.el, lisp/bbdb-srv.el, lisp/bbdb-sc.el, + lisp/bbdb-gui.el, lisp/bbdb-ftp.el, lisp/bbdb-com.el, + lisp/bbdb-hooks.el, lisp/bbdb-w3.el, lisp/bbdb.el, + lisp/bbdb-snarf.el: + Compiler cleanup + +2002-01-04 Robert Fenk + + * lisp/bbdb-snarf.el (bbdb-extract-address-component-regexps): + Replaced the call of bbdb-clean-username bt a call to + mail-extract-address-components in order to handle addresses of + the form "Lastname, Firstname" and "Firstname Lastname, Jr" in the + right way. + (bbdb-test/bbdb-extract-address-components): New test function to + check if everything is working as it should. + +2002-01-03 Robert Fenk + + * lisp/bbdb-com.el (bbdb-complete-name): fixed cycling when the + current completion is equal to one of the nets. + Added code for C-u M-TAB which lists all possible nets of current + completed addess. + +2002-01-01 Waider + + * lisp/bbdb-com.el (bbdb-complete-name): + Two fixes based on further testing with completion-type. + +2001-12-27 Waider + + * lisp/bbdb-com.el + (bbdb-completing-read-one-record): + Correctly handle case where no records are selected + (bbdb-complete-name): + Whoops. Small logic error in cycling code + + * lisp/bbdb.el (bbdb-send-mail-style), + lisp/bbdb-com.el (bbdb-send-mail-internal): + Add Mew as an option for bbdb-send-mail-style + +2001-12-27 Jeff Bigler + + * lisp/bbdb-com.el (bbdb-phone-area-regexp): + Allow / and . as separators when parsing a phone number. + +2001-12-26 Waider + + * lisp/bbdb-com.el (bbdb-complete-name): + Mostly rewritten to consolidate the last four years(!) of code + glomming. + + * lisp/bbdb.el (bbdb-search-intertwingle): + New function. More stringent version of bbdb-search-simple, + intended for internal bbdb use only + +2001-12-10 Karl Fogel + + * bbdb.texinfo + (Mail Sending Interfaces): + Use `add-hook' instead of `setq' in the examples, so users won't + clobber existing hooks. + (Known Bugs): + Reference mailing lists, as is done in other places where the + `bbdb-info' list is mentioned. + +2001-11-19 Waider + + * lisp/bbdb.el (bbdb-format-address): + Several people contributed a patch to fix this. Alex Schroeder's + was the most general as it handles both printing and + non-printing situations. + + * lisp/bbdb-print.el + Some more fixes from Alex. + +2001-11-12 Waider + + * lisp/bbdb-snarf.el (bbdb-extract-address-component-regexps): + Allow '+' as part of an email address + + * lisp/bbdb-com.el (bbdb-complete-name-allow-cycling): + Documentation fix + (bbdb-get-help-window): + Removed dead code + + * lisp/bbdb.el + Try to autoload the message-mode and mail-mode keymaps rather than + defining them as nil. + +2001-11-11 Waider + + * lisp/bbdb-vm.el (bbdb/vm-set-auto-folder-alist-field): + Move into mua-specific group + (bbdb/vm-set-auto-folder-alist): + Documentation typo + +2001-11-06 Waider + + * texinfo/bbdb.texinfo (Mail Sending Interfaces): + Mention message-setup-hook in the mail aliases section + (Raymond Scholz) + +2001-10-14 Waider + + * lisp/bbdb-gnus.el + (bbdb/gnus-pop-up-bbdb-buffer): + Move the call to bbdb-display-records back inside the (when...) + I had two bug reports for this (Sudesh Joseph and Michael + Totschnig). + + * lisp/bbdb.el: + Added Nix's patch to make inside-bbdb-notice-hook work as + advertised, also other bbdb-expire support. + (bbdb-search-simple): + Try company name if record name is unset, before falling back to + "". (Martin Schwenke) + + * lisp/bbdb-com.el + (bbdb-complete-name): + Restored the original code to handle making sure primary addresses + get picked first, since the code I'd replaced it with had some + dubious side-effects. + (bbdb-create-internal): + Documentation fix. (Ueli Schläpfer) + +2001-09-20 Robert Fenk + + * lisp/bbdb.el (bbdb-create-hook), (bbdb-notice-hook): + Added a note that hook functions might use the new variables + bbdb-update-address-class and bbdb-update-address-header to obtain + information about the currently processed email address. + + * lisp/bbdb-com.el (bbdb-get-addresses-headers): merged + bbdb-get-addresses-from-headers and bbdb-get-addresses-to-headers + into this variable. + (bbdb-get-addresses): new generic function for extraction of email + addresses from header, which is used by Gnus and VM + (bbdb-update-address-class), (bbdb-update-address-header): new + variable providing additional information to hook functions about + the currently processed email address. + + * lisp/bbdb-gnus.el (bbdb/gnus-update-records): uses + bbdb-get-addresses instead of bbdb/gnus-get-addresses which was + removed. + (bbdb/gnus-show-sender), (bbdb/gnus-show-all-recipients), + (bbdb/gnus-show-records): modified to use new style of + bbdb-get-addresses-headers + + * lisp/bbdb-vm.el (bbdb/vm-get-header-content): VM specific header + extraction function. + (bbdb/vm-update-records): bbdb-get-addresses instead of + bbdb/vm-get-addresses which was removed. + (bbdb/vm-show-all-recipients), + (bbdb/vm-show-sender), (bbdb/vm-show-records): modified to use new + style of bbdb-get-addresses-headers + + * lisp/bbdb-hooks.el (bbdb-auto-notes-alist): Additional element + type to allow actions also on recipients of an message + (bbdb-auto-notes-hook): Fixed to perfom auto-note actions only for + authors of a message. Support for new features of + bbdb-auto-notes-alist. Honor bbdb-silent-running. + +2001-09-18 Waider + + * lisp/bbdb-snarf.el (bbdb-rfc822-addresses): + Cope with rfc822-addresses returning nil as the car. + +2001-09-11 Robert Fenk + + * lisp/bbdb-print.el (bbdb-print-field-shown-p): Added as a + replacement for bbdb-field-shown-p. + (bbdb-print-omit-fields): Added as a replacement for + bbdb-print-elided-display. + + * lisp/bbdb-com.el (bbdb-get-addresses-headers): + bbdb-auto-notes-alist does not know if a address comes form a + author or recipient of a message and therefore might update wrong + records, e.g. the organization of recipients to that of the + author. + Therfore the default is now bbdb-get-addresses-from-headers until + the hook functions are able to tell the type (author/recp) of an + address. + +2001-09-09 Waider + + * lisp/bbdb-gui.el: + Fixed bogus fset (fsetting variable instead of 'variable) + (bbdb-hack-x-face): + use bbdb-find-face, not find-face + + * lisp/bbdb.el + (bbdb-initialize): + Fixed vm entry. vm-load-hook no longer exists! + (bbdb-mode): + Removed references to bbdb-elide-record + +2001-09-05 Robert Fenk + + * lisp/bbdb-com.el (bbdb-complete-name-hooks): Fixed the + documentation. + (bbdb-get-only-first-address-p): fixed the default value, which + should have been t + +2001-09-04 Robert Fenk + + * lisp/bbdb.el (bbdb-annotate-message-sender): calling of + bbdb-create-hook functions moved to the end of function + (bbdb-display-layout-alist): replaced by the nice version + provided by Alex Schroeder + +2001-08-31 Robert Fenk + + * lisp/bbdb-hooks.el (bbdb-auto-notes-alist): applied posted + patch of better customization. + + * lisp/bbdb-srv.el, lisp/bbdb-rmail.el, lisp/bbdb-mhe.el, + lisp/bbdb-vm.el, lisp/bbdb-gnus.el, lisp/bbdb.el, + lisp/bbdb-com.el: replaced occureneces of bbdb-elided-display and + bbdb-pop-up-elided-display. + + * lisp/bbdb-gui.el (build-bbdb-menu): Fix menus to use new display + layout toggeling functions. + + * lisp/bbdb-com.el (bbdb-change-records-state-and-redisplay), + (bbdb-toggle-all-records-display-layout), + (bbdb-toggle-records-display-layout), + (bbdb-display-all-records-completely), + (bbdb-display-record-completely): modified functions for toggeling + the display layout of records. Old functions bbdb-elide-record + and bbdb-unelide-records have been removed. + + * lisp/bbdb.el + (bbdb-display-layout-alist): variable controling options for + display layouts, support for user defines format functions still + missing. + (bbdb-display-layout): variable controling the default display layout + (bbdb-pop-up-display-layout): variable controling the default display + layout for pop-up buffers. + (bbdb-elided-display), (bbdb-pop-up-elided-display): are obsolete + variables now. + (bbdb-elided-display-sanity-setup): function which sets up the + layout variables from the obsolete bbdb-elided-display and + bbdb-pop-up-elided-display variables. Might be removed along with + the variables in the future. + (bbdb-format-record): rewitten to support multiple + layouts according to bbdb-display-layout-alist + (bbdb-format-record-layout-multi-line), + (bbdb-format-record-layout-one-line), + (bbdb-format-record-one-line-*): Function specific to certain + layouts. + +2002-01-13 Steve Youngs + + * package-info.in (provides): Update to include all provides. + +2002-01-07 Adrian Aichner + + * Makefile (HTML_FILES): New. + * Makefile (HTML_DEP): New. + +2001-08-29 Steve Youngs + + * Makefile (MAINTAINER): Change to Ronan Waide + . + +2001-08-26 Steve Youngs + + * lisp/bbdb.el (bbdb-initialize): Autoload it. + +2001-08-13 Jeff Mincy + + * lisp/bbdb-gui.el (bbdb-hack-x-face): Fix call to make-glyph. + +2001-07-01 Steve Youngs + + * Import BBDB 2.32 + +2000-11-07 Martin Buchholz + + * ./texinfo/bbdb.texinfo: Doc fix. + +2000-10-05 Martin Buchholz + + * *: Mega typo fix. + +2000-08-22 Steve Youngs + + * Makefile: Remove target 'clean' because it's covered in XEmacs.rules + +2000-08-16 Andreas Jaeger + + * Makefile (REQUIRES): Require w3 for base64. + +1999-01-24 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00.06 released + +1999-01-24 Colin Rafferty + + * lisp/bbdb-gnus.el: (bbdb/gnus-score-as-text) Handle the fact + that `score' could be either an int or a string. + +1999-01-21 Colin Rafferty + + * lisp/bbdb-com.el (bbdb-info): Made it work with Info-directory-list + +1999-01-21 Sam Steingold + + * lisp/bbdb.el (bbdb-display-records-1): bind + `temp-buffer-setup-hook' and `temp-buffer-show-hook' to nil. + This fixes the problem of `view-mode' conflicting with + `bbdb-mode'. + +1999-01-08 Jean-Yves Perrier + + * lisp/bbdb-comp.el (bbdb-redisplay-records): Don't bug out + with mark. + +1999-01-08 Colin Rafferty + + * lisp/bbdb.el (bbdb-string-trim): Make it remove *all* text + properties from the string instead of just a few select ones. + Inspired by Sam Steingold . + +1999-01-08 Sam Steingold + + * lisp/bbdb.el (bbdb-save-db-timeout): Correct comment. + +1998-12-31 Matt Simmons + + * lisp/bbdb-snarf.el (bbdb-snarf-region): Autoload + +1998-12-31 Colin Rafferty + + * lisp/bbdb-gnus.el (bbdb/gnus-snarf-signature): Created + +1998-12-31 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00.05 released + +1998-12-31 Matt Simmons + + * INSTALL: Added documentation for those without make + * lisp/bbdb-snarf.el: Merge in 1.8.1.x subtree + +1998-12-30 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00.04 released + +1998-12-29 Colin Rafferty + + * lisp/bbdb-com.el (bbdb-current-field): Made it handle the + blank user. + +1998-12-24 Colin Rafferty + + * lisp/bbdb.el (bbdb-version): Made it take an option to output in + current buffer. + +1998-12-10 Colin Rafferty + + * lisp/bbdb.el (bbdb-load-hook): Moved after the provide. + * lisp/bbdb.el (bbdb-display-records-1): Fix bug so that it + doesn't blow out on null records parameter. + +1998-12-07 Colin Rafferty + + * lisp/bbdb-snarf.el (bbdb-snarf-web-prop): Fix it to be a symbol. + * lisp/bbdb-snarf.el (bbdb-merge-internally): Use + bbdb-record-set-raw-notes. + +1998-12-05 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00.03 released + +1998-12-03 Adam C. Finnefrock + + * lisp/bbdb-gnus.el (bbdb/gnus-update-record): Honor + bbdb-user-mail-names. + +1998-11-17 Colin Rafferty + + * lisp/bbdb-gnus.el (bbdb/gnus-show-sender): Use currently + selected summary line rather than what may be in *Article* + buffer. + * lisp/bbdb-gnus.el (bbdb/gnus-edit-notes): ditto + * lisp/bbdb-gnus.el (bbdb/gnus-annotate-sender): ditto + +1998-11-09 Didier Verna + + * lisp/bbdb-xemacs.el (bbdb-fontify-buffer): extent-data is + obsolete (and gone in XEmacs 21.2+). Replace it. + * lisp/bbdb-xemacs.el (bbdb-menu): ditto. + +1998-10-27 Colin Rafferty + + * bbdb-com.el (bbdb-dwim-net-address-allow-redundancy): Created. + * bbdb-com.el (bbdb-dwim-net-address): As inspired by Xavier Francois + Vigouroux, use `bbdb-dwim-net-address-allow-redundancy'. + +1998-10-23 Colin Rafferty + + * lisp/bbdb.el: Changed mail list name from info-bbdb to + bbdb-info. + + * lisp/bbdb-print.el: Changed mail list name from info-bbdb to + bbdb-info. + + * texinfo/bbdb.texinfo: Changed mail list name from info-bbdb to + bbdb-info. + +1998-10-13 Colin Rafferty + + * bbdb-snarf.el (bbdb-snarf-web-prop): Made it a symbol. + +1998-10-13 Colin Rafferty + + * lisp/bbdb-com.el (bbdb-read-new-record): Check for integerp + explicitly with bbdb-default-area-code, instead of relying on + condition-case. + + * lisp/bbdb-print.el (bbdb-print-alist-widget): ditto. + * lisp/bbdb-print.el (bbdb-print-alist): ditto. + +1998-10-12 Adam C. Finnefrock + + * lisp/bbdb-com.el (bbdb-info-file): Made it a choice, since nil didn't + match the type: file. + +1998-10-08 Colin Rafferty + + * lisp/bbdb.el (bbdb-version): BBDB 2.00.02 released + +1998-07-19 SL Baur + + * lisp/bbdb-migrate.el (bbdb-migration-query): Don't pass an + integer to concat. + + * lisp/bbdb.el (bbdb-y-or-n-p): raise-screen -> raise-frame, + screen-visible-p -> frame-visible-p, selected-screen -> + selected-frame. + * lisp/bbdb.el (bbdb-pop-up-bbdb-buffer-horizontally): + screen-width -> frame-width. + + * lisp/bbdb-xemacs.el (bbdb-fontify-buffer): set-extent-attribute + -> set-extent-property, set-extent-data -> set-extent-property. + * lisp/bbdb-xemacs.el (bbdb-hack-x-face): set-extent-data -> + set-extent-property. + + * lisp/bbdb-srv.el (bbdb/srv-handle-headers): Use new name for + set-window-buffer-dedicated. + +Sat Apr 11 00:28:17 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00.01 released + * lisp/bbdb.el (bbdb-mode-map): Added bindings + * lisp/bbdb.el (bbdb-mode-search-map): Created, bound search + functions to it. + * lisp/bbdb.el (bbdb-initialize): Gutted + * lisp/bbdb.el (bbdb-initialize-hook): Created + * lisp/bbdb.el (bbdb-load-hook): Changed documentation + * lisp/bbdb.el (advertized-bbdb-delete-current-field-or-record): + Began to remove support + * lisp/bbdb-com.el (bbdb-changed): Syntax error in comment + * lisp/bbdb-com.el (bbdb-phones): Changed prompt + * lisp/bbdb-com.el (bbdb-net): Changed prompt + * lisp/bbdb-com.el (bbdb-company): Changed prompt + * lisp/bbdb-com.el (bbdb-name): Changed prompt + * lisp/bbdb-com.el (bbdb): Changed prompt + * lisp/bbdb-com.el (advertized-bbdb-delete-current-field-or-record): + Began to remove support + * texinfo/bbdb.texinfo: Added EOL list. + * texinfo/bbdb.texinfo: EOL'd + advertized-bbdb-delete-current-field-or-record. + * texinfo/bbdb.texinfo: EOL'd GNUS support. + * texinfo/bbdb.texinfo: Documented bbdb-initialize-hook + * texinfo/bbdb.texinfo: Documented new bindings + +Fri Mar 13 00:00:00 1998 Colin Rafferty + + * lisp/bbdb.el (bbdb-initialize): Made the autoloads be + conditionally loaded. + * lisp/bbdb-com.el: Added ###autoload cookies. + * lisp/bbdb-ftp.el: Added ###autoload cookies. + * lisp/bbdb-gnus.el: Added ###autoload cookies. + * lisp/bbdb-hooks.el: Added ###autoload cookies. + * lisp/bbdb-mhe.el: Added ###autoload cookies. + * lisp/bbdb-migrate.el: Added ###autoload cookies. + * lisp/bbdb-print.el: Added ###autoload cookies. + * lisp/bbdb-reportmail.el: Added ###autoload cookies. + * lisp/bbdb-rmail.el: Added ###autoload cookies. + * lisp/bbdb-sc.el: Added ###autoload cookies. + * lisp/bbdb-snarf.el: Added ###autoload cookies. + * lisp/bbdb-srv.el: Added ###autoload cookies. + * lisp/bbdb-vm.el: Added ###autoload cookies. + * lisp/bbdb-w3.el: Added ###autoload cookies. + * lisp/bbdb-whois.el: Added ###autoload cookies. + * lisp/bbdb-xemacs.el: Added ###autoload cookies. + * lisp/auto-autoloads.el: Regenerated with new autoloads. + +Tue Mar 31 23:46:05 1998 Matt Simmons + + * lisp/bbdb-migrate.el (bbdb-migrate-change-dates-change-field): + Use %S instead of %s for error messages. + +Tue Mar 17 00:00:00 1998 Colin Rafferty + + * lisp/bbdb-hooks.el (bbdb-timestamp-hook): Made + `format-time-string' take two arguments for XEmacs 19.15. + * lisp/bbdb-hooks.el (bbdb-creation-date-hook): Same. + +Mon Mar 16 20:02:00 1998 Matt Simmons + + * Makefile: Fix for compatibility with other makes + +Sun Mar 15 23:46:00 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 2.00 released + +Fri Mar 13 01:52:00 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 1.91unoff released + +Wed Mar 12 15:37:86 1998 Colin Rafferty + + * lisp/bbdb.el (parse-bbdb-internal): Fixed the error message on + mismatched bbdb-file-format. + +Fri Feb 06 00:00:00 1998 Colin Rafferty + + * bbdb-com.el (bbdb-current-field): Made it correctly count the + number of lines of a specially-formatted note field. + +Mon Mar 09 23:25:00 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 1.90unoff released + * lisp/bbdb.el (defface): Fixed defface standin + * lisp/bbdb.el (bbdb-alist-with-header): Created widget for + bbdb-auto-notes-alist custom fix. + * lisp/bbdb.el (bbdb-create-hook): Default to bbdb-creation-date-hook + * lisp/bbdb.el (bbdb-change-hook): Default to bbdb-timestamp-hook + * lisp/bbdb.el (bbdb-initialize): Added autoload for bbdb-srv + * Makefile: Removed my paths + * Makefile: Added 19.34 comment about Custom + * Makefile: Started test harness for 19.34 and 20.2 + * INSTALL: Added 19.34 comment about Custom + * lisp/Makefile: Fixed 19.34 problem with custom (:link bug) + * lisp/bbdb-hooks.el (bbdb-auto-notes-alist): Fixed customization + * lisp/bbdb-srv.el (bbdb/srv-handle-headers): buffer-disable-undo + doesn't always return the argument + * texinfo/bbdb.texinfo: Finished revisions. + +Mon Mar 09 03:03:21 1998 Carsten Leonhardt + + * lisp/bbdb-xemacs.el (bbdb-fontify-buffer): don't access + scrollbars on XEmacsen without scrollbars + +Mon Mar 02 00:00:00 1998 Colin Rafferty + + * bbdb-com.el (bbdb-refile-notes-generate-alist): Created. + * bbdb-com.el (bbdb-refile-notes-default-merge-function): Created. + * bbdb-com.el (bbdb-refile-notes-remove-duplicates): Created. + * bbdb-com.el (bbdb-refile-notes-string-least): Create. + * bbdb-com.el (bbdb-refile-record): Use `bbdb-refile-notes-generate-alist' + and `bbdb-refile-notes-default-merge-function' for merging notes. + +Wed Feb 25 23:35:00 1998 Matt Simmons + + * lisp/bbdb-print.el (bbdb-print-alist-widget): Protect bbdb-default-area-code + * lisp/bbdb-print.el (bbdb-print-alist): Protect bbdb-default-area-code + * lisp/bbdb-com.el (bbdb-read-new-record): Protect bbdb-default-area-code + * lisp/bbdb-com.el (bbdb-prompt-for-new-field-value): Protect bbdb-default-area-code + * lisp/bbdb-com.el (bbdb-dial): Protect bbdb-default-area-code + +Sat Jan 16 00:00:00 1998 Colin Rafferty + + * lisp/Makefile (extras): fixed typo in bbdb-migrate.elc + +Sun Feb 22 20:58:00 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 1.59unoff released + * lisp/bbdb.el: Created defface stand-in macro + * lisp/bbdb.el (bbdb-initialize): Reword + * lisp/bbdb.el (bbdb-initialize): Add keybinding for bbdb-print + * lisp/bbdb.el (bbdb-initialize): Add autoloads for + bbdb-show-all-recipients (bbdb-com), bbdb-ftp, bbdb-print + * lisp/bbdb.el (bbdb-initialize): Use bbdb-add-hook if none in Emacs + * lisp/bbdb-ftp.el: Changed comment - can use EFS + * lisp/bbdb-gnus.el: Changed GNUS/Gnus stuff around to reflect docs + * lisp/bbdb-gnus.el (bbdb/gnus-summary-author-in-bbdb): Now uses + `bbdb-message-marker-field' as documented + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Use `add-hook', not + `bbdb-add-hook' + * lisp/bbdb-hooks.el: Use add-hook, not bbdb-add-hook + * lisp/bbdb-mhe.el: Use add-hook, not bbdb-add-hook + * lisp/bbdb-rmail.el: Use add-hook, not bbdb-add-hook + * lisp/bbdb-vm.el: Use add-hook, not bbdb-add-hook + * lisp/bbdb-xemacs.el: Use add-hook, not bbdb-add-hook + * lisp/bbdb-print.el: Moved key binding to bbdb.el + * lisp/bbdb-print.el: Changed default of `bbdb-print-elide' + * lisp/bbdb-print.el (bbdb-print-alist-widget): Fixed problem with + nil `bbdb-default-area-code' + * lisp/bbdb-sc.el: Fixed intro comments + * lisp/bbdb-sc.el: Use add-hook, not bbdb-add-hook + * Makefile: Alphabetized MUA directory variables, added OTHERDIR + variable + * lisp/Makefile: Support for OTHERDIR, rearranged flags to Emacs + so we can use bbdb-split-string (19.34 doesn't have split-string) + * texinfo/bbdb.texinfo: Almost finished doc rewrite + * misc/bbdb_gnus-summary-get-author.fig: Created + +Fri Feb 20 19:31:00 1998 Christopher Kline + + * texinfo/bbdb.texinfo: Documentation for BBDB-Reportmail + +Thu Feb 19 13:41:17 1998 Sam Steingold + + * lisp/bbdb.el (bbdb-version): Return a string if non-interactive + +Mon Jan 5 20:40:03 1998 Matt Simmons + + * lisp/bbdb.el: BBDB 1.58unoff released + * lisp/auto-autoloads.el: Removed all autoloads except `bbdb-initialize' + * lisp/bbdb-com.el: Fixed copyright + * lisp/bbdb-com.el: Removed autoloads + * lisp/bbdb-com.el: Finger group changed + * lisp/bbdb-com.el (bbdb-compare-records): Changed to backquote notation + * lisp/bbdb-ftp.el: Customized + * lisp/bbdb-ftp.el: Added provide of bbdb-ftp + * lisp/bbdb-gnus.el: Removed autoloads + * lisp/bbdb-gnus.el (bbdb/gnus-summary-prefer-real-names): Reformatted doc + * lisp/bbdb-gnus.el (bbdb/gnus-score-as-text): Remove `when' + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Remove `when' + * lisp/bbdb-hooks.el: Added provide of bbdb-hooks + * lisp/bbdb-hooks.el (bbdb-time-internal-format): Replaces bbdb-time-string + * lisp/bbdb-hooks.el (bbdb-ignore-most-messages-alist): Fixed custom spec + * lisp/bbdb-hooks.el (bbdb-ignore-some-messages-alist): Fixed custom spec + * lisp/bbdb-hooks.el (bbdb-auto-notes-alist): Fixed custom spec + * lisp/bbdb-hooks.el (bbdb-auto-notes-ignore): Fixed custom spec + * lisp/bbdb-hooks.el (bbdb-auto-notes-ignore-all): Fixed custom spec + * lisp/bbdb-migrate.el: Created from migrate code in bbdb.el + * lisp/bbdb-print.el: Customized + * lisp/bbdb-print.el: Removed autoloads + * lisp/bbdb-reportmail.el: Changed setup docs, added RCS ID and Log strings + * lisp/bbdb-sc.el: Fixed jwz's e-mail address + * lisp/bbdb-sc.el: Customized + * lisp/bbdb-sc.el: Removed autoloads + * lisp/bbdb-sc.el: Added provide of bbdb-sc + * lisp/bbdb-snarf.el: Customized + * lisp/bbdb-snarf.el: Removed autoloads + * lisp/bbdb-srv.el: Rearranged copyright + * lisp/bbdb-srv.el: Customized + * lisp/bbdb-w3.el: Removed autoloads + * lisp/bbdb-w3.el: Added provide of bbdb-w3 + * lisp/bbdb-whois.el: Added to copyright + * lisp/bbdb-whois.el: Customized + * lisp/bbdb-xemacs.el: Removed autoloads + * lisp/bbdb.el: Added define-widget definition for users without Custom + * lisp/bbdb.el: Added utilities custom groups + * lisp/bbdb.el: Removed migration code + * lisp/bbdb.el: Commented some code + * lisp/bbdb.el (bbdb-string-trim): Delete still more text properties + * lisp/bbdb.el (bbdb-save-db): Made error message slightly more obvious + * lisp/bbdb.el (bbdb-initialize): Added symbols for selective insinuation + * lisp/bbdb.el (bbdb-initialize): Rearranged and added some autoloads + * Makefile: Added migrate.el + * Makefile: Added deploy target + * texinfo/bbdb.texinfo: Changed `setq' to `add-hook' in setup instructions + * texinfo/bbdb.texinfo: Added to Internals section + +Mon Dec 1 09:00:12 1997 Matt Simmons + + * lisp/bbdb.el: BBDB 1.57Aunoff released + * texinfo/bbdb.texinfo: Documented new startup procedure + * INSTALL: Documented new startup procedure + +Sun Nov 30 23:26:21 1997 Matt Simmons + + * lisp/bbdb.el: BBDB 1.57unoff released + +Sun Nov 30 22:47:04 1997 Sam Steingold + + * lisp/bbdb-hooks.el (bbdb-time-string): Uses format string now + * lisp/bbdb-com.el (bbdb-display-some): Added + * lisp/bbdb-com.el (bbdb-kill-older): Created + * lisp/bbdb-com.el (bbdb-timestamp-older): Created + * lisp/bbdb-com.el (bbdb-timestamp-newer): Created + * lisp/bbdb-com.el (bbdb-creation-older): Created + * lisp/bbdb-com.el (bbdb-creation-newer): Created + +Sun Nov 30 22:44:42 1997 Matt Simmons + + * lisp/auto-autoloads.el: Autoloads for date functions + * lisp/bbdb-com.el (bbdb-complete-clicked-name): Make 19.34 happy + * lisp/bbdb-com.el (bbdb-compare-records): Created + * lisp/bbdb-com.el: Customized variables + * lisp/bbdb-gnus.el: Customized variables + * lisp/bbdb-hooks.el: Customized variables + * lisp/bbdb.el: Customized variables + * lisp/bbdb.el: Added timezone require to support date functions + * lisp/bbdb.el: Added migration functions, changed database version + * lisp/bbdb.el: Added definitions for utility functions that don't + appear in all Emacsen (in the case of string>, in none) + * lisp/bbdb.el (defstruct): Added documentation + * lisp/bbdb.el (bbdb-format-record): Can now define printing + functions for each note field + (bbdb-format-record-fieldname) + * lisp/bbdb.el (bbdb-copy-thing): Created + * lisp/bbdb.el (bbdb-initialize): Created - Use it to initialize + * texinfo/Makefile (clean): Changed since we now distribute *.info* + * texinfo/Makefile (reallyclean): clean + removes *.info* + * texinfo/bbdb.texinfo: Removed `BBDB database' per jwz, added + prereq section, more special fields, some + internals. + * INSTALL: Created + +Thu Oct 30 07:06:15 1997 Hrvoje Niksic + + * lisp/bbdb.el: Custom blob to make defcustom and defgroup + transparent in non-customized Emacsen + +Sun Nov 30 12:03:41 1997 Soren Dayton + + * lisp/bbdb-print.el (bbdb-print-tex-quote): Escape tildes properly + +Tue Nov 10 20:10:53 1997 Jens-Ulrik Holger Petersen + + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Improve output of + warning messages. + * lisp/bbdb-gnus.el (bbdb/gnus-summary-known-poster-mark): Correct + docstring. + +Sat Nov 8 17:00:21 1997 Matt Simmons + + * lisp/bbdb.el (bbdb-string-trim): Just remove 'face property. + * lisp/bbdb.el: Define `defvaralias' as empty function if it's not + defined. (GNU Emacs doesn't have it) + +Sun Nov 2 01:32:23 1997 Matt Simmons + + * lisp/bbdb.el: BBDB 1.56unoff released + * lisp/bbdb-sc.el: Added + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Commented back in score + hook addition, can now set up format functions one at a time + (latter based on function from Christoph Wedler) + * lisp/bbdb-gnus.el (bbdb/gnus-score-default-internal): Added to + automagically catch changes to `bbdb/gnus-score-default'. + * lisp/bbdb-gnus.el (bbdb/gnus-annotate-sender): Now takes REPLACE + argument. + * lisp/bbdb-vm.el (bbdb/vm-annotate-sender): Ditto + * lisp/bbdb-mhe.el (bbdb/mh-annotate-sender): Ditto + * lisp/bbdb-rmail.el (bbdb/rmail-annotate-sender): Ditto + * lisp/auto-autoloads.el: Support for bbdb-sc, housekeeping for others. + * Makefile (install-pkg): Bug fix. + * texinfo/bbdb.texinfo: More rewriting, documentation for the + Summary Buffer stuff in bbdb-gnus.el + +Tue Oct 28 16:08:54 1997 Christoph Wedler + + * lisp/bbdb-gnus.el (bbdb/gnus-define-format-functions): New + variable. + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Use it. Only define user + functions the first time. Use `bbdb-warn' instead `error'. + * lisp/bbdb.el (bbdb-warn): New function. Use it. + +Sun Oct 26 20:47:20 1997 Matt Simmons + + * lisp/auto-autoloads.el: Remove summary buffer autoloads + * lisp/bbdb-gnus.el: Variable aliases for backward compatibility + * lisp/bbdb-gnus.el (bbdb/gnus-summary-user-format-letter): Add + more descriptive documentation. + * lisp/bbdb-gnus.el (bbdb/gnus-summary-in-bbdb-format-letter): Added + * lisp/bbdb-gnus.el (bbdb/gnus-lines-and-from): Variable name change + * lisp/bbdb-gnus.el (bbdb/gnus-summary-author-in-bbdb): Added + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Commented out score + insinuation, add %ub summary line code creation + * lisp/bbdb.el: Remove summary buffer autoloads + +Sun Oct 26 00:14:36 1997 Matt Simmons + + * lisp/bbdb.el: BBDB 1.55unoff released + * texinfo/bbdb.texinfo: Partial rewrite + * lisp/bbdb.el: new autoloads. Override bbdb-display-completion-list + for XEmacs users. + * lisp/bbdb-w3.el (bbdb-www): Uses browse-url-browser-function + instead of a manual funcall + * lisp/bbdb-snarf.el (bbdb-snarf-region): Toss trailing space too + +Sat Oct 25 23:47:40 1997 Brian Edmonds +Sat Oct 25 23:47:40 1997 Matt Simmons + + * lisp/bbdb-gnus.el: Changed *everything* beginning with + `gnus-bbdb' to `bbdb/gnus' + * lisp/bbdb-gnus.el (bbdb/gnus-summary-get-author): Integrated (along + with associated variables and functions) + * lisp/bbdb-gnus.el (bbdb/gnus-score): Integrated (along with + associated variables and functions) + * lisp/bbdb-gnus.el (bbdb-insinuate-gnus): Activate above new + features + +Sat Oct 25 17:54:26 1997 Marco Walther +Sat Oct 25 17:54:26 1997 Matt Simmons + + * lisp/bbdb-com.el (bbdb-complete-name): Clicking on name in + completion buffer now restores configuration (uses callback below) + * lisp/bbdb-com.el (bbdb-complete-clicked-name): Created. See above + * lisp/bbdb-com.el (bbdb-display-completion-list): Wrapper + * lisp/bbdb-xemacs.el (bbdb-xemacs-display-completion-list): + XEmacs version of bbdb-display-completion-list, allows callbacks + * lisp/auto-autoloads.el: autoload for XEmacs version of + bbdb-display-completion-list + +Mon Oct 20 18:38:28 1997 Colin Rafferty + + * Makefile (install-pkg): Made it install the el before the .elc. + +Mon Oct 20 12:15:15 1997 Christoph Wedler + + * lisp/bbdb-xemacs.el (global-bbdb-menu-commands): Bug fix "Finger + All Records". + * lisp/bbdb-xemacs.el (build-bbdb-finger-menu): Use + `bbdb-record-finger-host'. + * lisp/bbdb-com.el (bbdb-finger): Doc string extension. + * texinfo/bbdb.texinfo (BBDB Mode): Add documentation for + `bbdb-finger'. + +Tue Oct 14 20:06:38 1997 david carlton + + * Makefile (install-pkg): Fix info linking - use texinfo, not info + +Mon Oct 13 16:41:27 1997 Soren Dayton + + * lisp/bbdb-w3.el (bbdb-www): Use browse-url instead of funcalling + contents of browse-url-browser-function. + +Sat Oct 11 19:19:27 1997 Matt Simmons + + * bbdb.el: BBDB 1.54unoff released + * lisp/Makefile: Changed VM, GNUS, and MHE definitions so they can + be blank if the packages are in load-path. Added bbdb-snarf and + bbdb-w3. Made bbdb-srv and bbdb-reportmail skipping messages more + informative. Added check for itimer for bbdb-srv. + * lisp/bbdb-w3.el (bbdb-insinuate-w3): Created from bare add-hook + statement found in David's version. Add this to w3-mode-hook + (yes, that's singular, not plural) + * lisp/bbdb-w3.el (bbdb-www): Modified to use + browse-url-browser-function instead of having two functions, one + for netscape and one for w3. + * lisp/bbdb-snarf.el: Fixed area code pattern to use [2-9] instead + of [0-9] for first digit. + * lisp/auto-autoloads.el: Autoloads for bbdb-snarf, bbdb-www, + changed package dir from `bbdb-1.52' to `bbdb', autoload for + bbdb-insinuate-message. + * lisp/bbdb.el: Added autoloads for bbdb-insinuate-message, + bbdb-www, bbdb-www-grab-homepage, bbdb-insinuate-w3, bbdb-snarf. + * lisp/bbdb.el (bbdb-mode): Documentation for bbdb-www `w' keystroke + * lisp/bbdb.el (bbdb-mode-map): bbdb-www invocation + * lisp/bbdb.el (bbdb-split): Documented. + * lisp/bbdb-gnus.el (bbdb-insinuate-message): Use it. Sets the + M-t binding for message-mode. This isn't in bbdb-insinuate-gnus + because some like to use message-mode before loading gnus. Add + it to `message-setup-hook', _not_ `message-load-hook'. + +Sat Oct 11 19:01:00 1997 David Carlton + + * lisp/bbdb-w3.el: Added to bbdb distribution. I don't know who + the original author is, but David mailed it to me. + +Sat Oct 11 19:00:00 1997 John Heidemann + + * lisp/bbdb-snarf.el: Added to bbdb distribution. Grabs text from + paragraph around point and makes a bbdb record out of it. See + the source for docs until I get around to adding to the texinfo + file. + +Sat Oct 11 18:50:52 1997 Kees de Bruin + + * lisp/bbdb-vm.el (bbdb/vm-alternate-full-name): make VM use the + canonicalized net address instead of the default address. + * lisp/bbdb-com.el (bbdb-sendmail-internal): Still more + message-mode fixes. Default to message-mode if neither mh-e nor + vm are in `features'. If message-mode is to be used and it's not + loaded, autoload it. + +Thu Oct 9 06:37:00 1997 Matt Simmons + * lisp/Makefile: Check for itimer before building bbdb-srv. + Complain nicely when check fails. + +Sun Oct 5 20:16:00 1997 Matt Simmons + * bbdb.el: BBDB 1.53unoff released + +Sun Oct 5 19:53:12 1997 Boris Goldowsky + * tex/bbdb-cols.tex, tex/bbdb-print-brief.tex, tex/bbdb-print.tex, + lisp/bbdb-print.el: New version of bbdb-print + +Sun Oct 5 19:51:21 1997 Jamie Zawinski + * utils/bbdb-cid.pl, utils/bbdb-src.pl, utils/bbdb-to-netscape.el: + New utilities + * lisp/bbdb-com.el (bbdb-parse-phone-number): Changed comment to + reflect new area codes that don't have [012] as their second digit + * lisp/bbdb-srv.el (bbdb/srv-auto-create-mail-news-dispatcher): + Classification of messages as mail or news + * lisp/bbdb-srv.el (bbdb-src-add-phone): Supports caller ID util + * lisp/bbdb-srv.el (bbdb/srv-handle-headers): Make sure *BBDB* is + bottommost buffer + +Sun Oct 5 19:51:20 1997 Seth Golub + * utils/bbdb-areacode-split.pl: New utility + +Sun Oct 5 19:51:19 1997 Matt Simmons + + * A grand reorg: .tex files -> tex subdirectory, + .texinfo files -> texinfo subdirectory, + .el files -> lisp subdirectory, + * Makefile: modified all Makefiles to deal with reorg, + rewrote XEmacs package section + * lisp/bbdb.el (bbdb-frob-mode-line): I like version numbers on modelines + * lisp/bbdb.el (bbdb-version-date): Separate date from version number + * lisp/bbdb.el (bbdb-version): Modified to deal with version + number separate from date + +Mon Sep 29 18:49:47 1997 Matt Simmons + + * Makefile: patch to avoid building bbdb-srv and bbdb-reportmail + if gnuserv and reportmail (respectively) aren't present + * bbdb.el (bbdb-frob-mode-line): Print the version number on the + mode line + +Sun Sep 28 00:50:07 1997 Matt Simmons + + * bbdb.el: BBDB 1.52unoff released + * bbdb.el (bbdb-y-or-n-p): Fix obsolete functions + * bbdb-ftp.el: Added check for efs + * Makefile: renamed it, removed mail-extr and mail-abbrev, did + some reformatting + +Sun Sep 28 00:49:00 1997 Colin Rafferty + + * auto-autoloads.el, Makefile: Use BBDB as an XEmacs package + +Sun Sep 28 00:03:31 1997 Jens-Ulrik Hoger Petersen + + * bbdb-gnus.el (bbdb/gnus-update-record): Changed method for + referencing article buffer. Needed when + gnus-single-article-buffer is nil. + * bbdb-hooks.el (bbdb-header-start): See above. + +Sat Sep 27 23:56:35 1997 Christopher Kline + + * bbdb-reportmail.el: Created + +Sat Sep 27 23:47:01 1997 Soren Dayton + + * bbdb-com.el (bbdb-send-mail-internal): Allow use of message-mail + * bbdb.el (bbdb-send-mail-style): Documentation change. See above. + +Sat Sep 27 23:44:43 1997 Colin Rafferty + + * bbdb.el (bbdb-annotate-message-sender): Use address for name if no name + +Sat Sep 27 23:39:09 1997 Christoph Wedler + + * bbdb-com.el (bbdb-finger-host-field): Added code to check for + finger-host field. Finger is done on finger-host if it + exists, on net address otherwise. + +Sat Sep 27 20:06:05 1997 Matt Simmons + + * bbdb-com.el (bbdb-phone-area-regexp): Fix US area code pattern diff --git a/xemacs-packages/lisp/bbdb/INSTALL b/xemacs-packages/lisp/bbdb/INSTALL new file mode 100644 index 00000000..9cba0732 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/INSTALL @@ -0,0 +1,166 @@ +This file has three sets of installation instructions: with `make', +without `make', and uncompiled. Please follow the appropriate set of +instructions. If you plan on running BBDB directly from CVS, please +check the additional instructions below. + +=============================================================================== + +Running BBDB from CVS: + + *** PLEASE NOTE **** + This applies to the master CVS tree at sourceforge, not the XEmacs CVS tree. + *** PLEASE NOTE *** + + This is not recommended, unless you're a BBDB developer. You will + need to either install the GNU autoconf package, or download the + pregenerated copy of configure from the BBDB website. If you choose + the former option, you'll need to run `autoconf' to generate the + configure script. Thereafter, follow the appropriate set of + instructions below. + +=============================================================================== + +To compile and install the BBDB on systems with `make': + + 1) Configure the compilation process: + + First of all, you should run the `configure' script at the toplevel of + the distribution. This script will perform a number of checks on your + system and generate the Makefile's accordingly. + + The `configure' script comes with a number of options that might be of + interest to you: + + `--with-emacs=PROG' lets you select an Emacs program to use. By + default, "emacs" and "xemacs" will be tried in that order. + + `--with-{gnus,mhe,vm}-dir=DIR' let you specify the paths where Gnus, + MH-E and VM can respectively be found, if Emacs can't find them by + itself (like, if they're not in the load-path by default). + + `--with-other-dirs=DIRS' lets you specify additional paths (space or + colon spearated) to find other libraries that might be needed (see + the "Byte Compiling the Lisp files" section of the BBDB manual for + more information). + + NOTE: Gnu Emacs 19.34 users should add the path to Custom 1.9962 + here if they plan to build Gnus support. Gnus support will not build + under Gnu Emacs 19.34 without Custom 1.9962. + + `--with-package-dir=DIR' lets you specify the installation path for + for XEmacs package installation. By default, + "/usr/local/lib/xemacs/site-packages" is used. + + `--with-symlinks' will make the installation process use symbolic links + to the sources instead of copying the files. + + `--with-linkpath=PATH' lets you specify the path to link from, if your + `pwd' command doesn't work properly. + + + 2) Build the BBDB: + + To build the BBDB with support for all of the supported mail + and news programs (gnus, mh-e, rmail, and vm), issue the + command 'make all'. (The BBDB also supports sendmail mode - + support for it is automatically compiled in, regardless of the + build options supplied) To build with support only for gnus, + mh-e, rmail, and/or vm, issue the 'make' command with one or + more of the following arguments: 'gnus', 'mh-e', 'rmail', + and/or 'vm'. To build the BBDB without support for any mail + program (except for sendmail mode), issue the command + 'make bbdb'. + + + 3) Install the BBDB: + + The three most typical installations are outlined below: + + a) In-place. + i) Follow steps 1 and 2 + ii) Add the lisp subdirectory to the Emacs load-path + iii) Add the tex subdirectory to the TeX + search path (can be done by adding the complete path + to the tex subdirectory to the environment variable + TEXINPUTS) + iv) Add the texinfo directory to the Info search path. + b) "Normal". + i) Follow steps 1 and 2. + ii) Copy the .el and .elc files from the lisp + subdirectory to a directory on the Emacs load-path + (or make a new directory, copy the files to it, and + add the new directory to the load-path). + iii) Copy the .tex files from the tex subdirectory to a + directory on the TeX search path (or make a new + directory, copy the files to it, and add the new + directory to the TeX search path. + iv) Copy the .info and .info-* files from the texinfo + subdirectory to a directory on the Info search path + (or make a new directory, copy the files to it, and + add the new directory to the Info search path) + c) XEmacs Package + NOTE: This installation option is only available to users + running XEmacs 20.3 or higher. + i) Follow steps 1 and 2. + ii) Issue the 'make install-pkg' command. + + + +To compile and install the BBDB on systems without `make': + + If at all possible, use make to automatically build the BBDB as + outlined above. While it looks like there are fewer steps in the + non-make instructions below, they're more tedious and involved. + + 1) Compile the .el files using the byte-compile-file function in + Emacs. + + 2) Install the BBDB as outlined in step 3 above. + +=============================================================================== + +To run BBDB uncompiled: + + Again, this is really not recommended, although it will generate a + more meaningful stacktrace if you happen to run into a problem. In + order to run BBDB uncompiled, you'll need to do two things: + + 1) Generate bbdb-autoloads.el + You can do this by typing 'make autoloads' in the main BBDB + directory. Note that this will require you to have previously run + configure to generate Makefiles. + + 2) Add .../bbdb/lisp to your load path + You need to make sure that the lisp subdirectory of the BBDB + source is in your load path so that Emacs can find the BBDB + files. + + Since arbitrary chunks of the BBDB are macros, you'll probably find + the uncompiled version slower than the compiled version. + +=============================================================================== + +*************************************************************************** +* * +* THE BBDB INITIALIZATION PROCEDURE CHANGED IN 1.57unoff. * +* * +* YOU *MUST* ADD * +* * +* (require 'bbdb) * +* (bbdb-initialize) * +* * +* TO YOUR BBDB INITIALIZATION CODE. THIS TAKES THE PLACE OF ALL BBDB * +* AUTOLOADS. IT DOES *NOT* TAKE THE PLACE OF THE INSINUATION CODE. * +* * +* If you do not add this code, you will receive keymap errors * +* (among other things) * +* * +*************************************************************************** + +For information on post-installation BBDB configuration and setup, see +the info file. (M-x bbdb, and press 'i' in the BBDB info window) + +Questions, Comments, Suggestions, and Bug Reports may be directed to +the BBDB mailing list at bbdb-info@lists.sourceforge.net. To +subscribe, send mail to bbdb-info-request@lists.sourceforge.net, with +'subscribe' as the subject. diff --git a/xemacs-packages/lisp/bbdb/README b/xemacs-packages/lisp/bbdb/README new file mode 100644 index 00000000..95dee723 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/README @@ -0,0 +1 @@ +Read the INSTALL file. diff --git a/xemacs-packages/lisp/bbdb/_pkg.el b/xemacs-packages/lisp/bbdb/_pkg.el new file mode 100644 index 00000000..f3a7e398 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/_pkg.el @@ -0,0 +1,5 @@ +;;;###autoload +(package-provide 'bbdb + :version 1.29 + :author-version "2.34" + :type 'regular) diff --git a/xemacs-packages/lisp/bbdb/auto-autoloads.el b/xemacs-packages/lisp/bbdb/auto-autoloads.el new file mode 100644 index 00000000..7259c97e --- /dev/null +++ b/xemacs-packages/lisp/bbdb/auto-autoloads.el @@ -0,0 +1,764 @@ +;;; DO NOT MODIFY THIS FILE +(if (featurep 'bbdb-autoloads) (error "Already loaded")) + +;;;### (autoloads nil "_pkg" "lisp/_pkg.el") + +(package-provide 'bbdb :version 1.29 :author-version "2.34" :type 'regular) + +;;;*** + +;;;### (autoloads (bbdb-update-records bbdb-help bbdb-info bbdb-creation-no-change bbdb-creation-newer bbdb-creation-older bbdb-timestamp-newer bbdb-timestamp-older bbdb-finger bbdb-dial bbdb-add-or-remove-mail-alias bbdb-define-all-aliases bbdb-yank bbdb-complete-name bbdb-read-addresses-with-completion bbdb-completion-predicate bbdb-completion-check-record bbdb-show-all-recipients bbdb-send-mail bbdb-dwim-net-address bbdb-sort-addresses bbdb-sort-phones bbdb-sort-notes bbdb-refile-record bbdb-omit-record bbdb-display-record-with-layout bbdb-display-record-completely bbdb-display-all-records-completely bbdb-toggle-records-display-layout bbdb-toggle-all-records-display-layout bbdb-delete-current-record bbdb-delete-current-field-or-record bbdb-transpose-fields bbdb-record-edit-property bbdb-record-edit-notes bbdb-edit-current-field bbdb-insert-new-field bbdb-append-records bbdb-append-records-p bbdb-apply-next-command-to-all-records bbdb-create bbdb-redisplay-records bbdb-changed bbdb-notes bbdb-net bbdb-company bbdb-name bbdb bbdb-search-invert-set) "bbdb-com" "lisp/bbdb-com.el") + +(autoload 'bbdb-search-invert-set "bbdb-com" "\ +Typing \\\\[bbdb-search-invert-set] inverts the meaning of the next search command. +Sets `bbdb-search-invert' to t. +You will have to call this function again, if you want to +do repeated inverted searches." t nil) + +(autoload 'bbdb "bbdb-com" "\ +Display all entries in the BBDB matching the regexp STRING +in either the name(s), company, network address, or notes." t nil) + +(autoload 'bbdb-name "bbdb-com" "\ +Display all entries in the BBDB matching the regexp STRING in the name +\(or ``alternate'' names)." t nil) + +(autoload 'bbdb-company "bbdb-com" "\ +Display all entries in BBDB matching STRING in the company field." t nil) + +(autoload 'bbdb-net "bbdb-com" "\ +Display all entries in BBDB matching regexp STRING in the network address." t nil) + +(autoload 'bbdb-notes "bbdb-com" "\ +Display all entries in BBDB matching STRING in the named notes field." t nil) + +(autoload 'bbdb-changed "bbdb-com" "\ +Display all entries in the bbdb database which have been changed since +the database was last saved." t nil) + +(autoload 'bbdb-redisplay-records "bbdb-com" "\ +Regrinds the contents of the *BBDB* buffer, without scrolling. +If possible, you should call `bbdb-redisplay-one-record' instead." nil nil) + +(autoload 'bbdb-create "bbdb-com" "\ +Add a new entry to the bbdb database ; prompts for all relevant info +using the echo area, inserts the new record in the db, sorted alphabetically, +and offers to save the db file. DO NOT call this from a program. Call +bbdb-create-internal instead." t nil) + +(autoload 'bbdb-apply-next-command-to-all-records "bbdb-com" "\ +Typing \\\\[bbdb-apply-next-command-to-all-records] in the *BBDB* buffer makes the next command operate on all +of the records currently displayed. (Note that this only works for +certain commands.)" t nil) + +(autoload 'bbdb-append-records-p "bbdb-com" nil nil nil) + +(autoload 'bbdb-append-records "bbdb-com" "\ +Typing \\\\[bbdb-append-records] in the *BBDB* buffer makes the next search/display command to append +new records to those in the *BBDB* buffer. + +With an prefix arg (C-u) toggle between always append and no append. +With an prefix arg that is a positive number append will be enabled for that +many times. +With any other argument append will be enabled once." t nil) + +(autoload 'bbdb-insert-new-field "bbdb-com" "\ +Add a new field to the current record; the field type and contents +are prompted for if not supplied. + +If you are inserting a new phone-number field, you can control whether +it is a north american or european phone number by providing a prefix +argument. A prefix arg of ^U means it's to be a euronumber, and any +other prefix arg means it's to be a a structured north american number. +Otherwise, which style is used is controlled by the variable +`bbdb-north-american-phone-numbers-p'. + +If you are inserting a new net address, you can have BBDB append a +default domain to any net address that does not contain one. Set +`bbdb-default-domain' to a string such as \"mycompany.com\" (or, +depending on your environment, (getenv \"DOMAINNAME\")), and +\"@mycompany.com\" will be appended to an address that is entered as +just a username. A prefix arg of ^U (or a `bbdb-default-domain' +value of \"\", the default) means do not alter the address." t nil) + +(autoload 'bbdb-edit-current-field "bbdb-com" "\ +Edit the contents of the Insidious Big Brother Database field displayed on +the current line (this is only meaningful in the \"*BBDB*\" buffer.) If the +cursor is in the middle of a multi-line field, such as an address or comments +section, then the entire field is edited, not just the current line." t nil) + +(autoload 'bbdb-record-edit-notes "bbdb-com" nil t nil) + +(autoload 'bbdb-record-edit-property "bbdb-com" nil t nil) + +(autoload 'bbdb-transpose-fields "bbdb-com" "\ +This is like the `transpose-lines' command, but it is for BBDB fields. +If the cursor is on a field of a BBDB record, that field and the previous +field will be transposed. + +With argument ARG, takes previous line and moves it past ARG fields. +With argument 0, interchanges field point is in with field mark is in. + +Both fields must be in the same record, and must be of the same basic type +\(that is, you can use this command to change the order in which phone-number +fields are listed, but you can't use it to make an address appear before a +phone number; the order of field types is fixed.)" t nil) + +(autoload 'bbdb-delete-current-field-or-record "bbdb-com" "\ +Delete the line which the cursor is on; actually, delete the field which +that line represents from the database. If the cursor is on the first line +of a database entry (the name/company line) then the entire entry will be +deleted." t nil) + +(autoload 'bbdb-delete-current-record "bbdb-com" "\ +Delete the entire bbdb database entry which the cursor is within. +Pressing \\\\[bbdb-apply-next-command-to-all-records] will +delete all records listed in the BBDB buffer." t nil) + +(autoload 'bbdb-toggle-all-records-display-layout "bbdb-com" "\ +Show all the fields of all visible records. +Like `bbdb-toggle-records-display-layout' but for all visible records." t nil) + +(autoload 'bbdb-toggle-records-display-layout "bbdb-com" "\ +Toggle whether the current record is displayed expanded or elided +\(multi-line or one-line display.) With a numeric argument of 0, the +current record will unconditionally be made elided; with any other argument, +the current record will unconditionally be shown expanded. +\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-toggle-records-display-layout]\" is used instead of simply \"\\[bbdb-toggle-records-display-layout]\", then the state of all records will +be changed instead of just the one at point. In this case, an argument +of 0 means that all records will unconditionally be made elided; any other +numeric argument means that all of the records will unconditionally be shown +expanded; and no numeric argument means that the records are made to be in +the opposite state of the record under point." t nil) + +(autoload 'bbdb-display-all-records-completely "bbdb-com" "\ +Show all the fields of all currently displayed records. +The display layout `full-multi-line' is used for this." t nil) + +(autoload 'bbdb-display-record-completely "bbdb-com" "\ +Show all the fields of the current record. +The display layout `full-multi-line' is used for this." t nil) + +(autoload 'bbdb-display-record-with-layout "bbdb-com" "\ +Show all the fields of the current record using LAYOUT." t nil) + +(autoload 'bbdb-omit-record "bbdb-com" "\ +Remove the current record from the display without deleting it from the +database. With a prefix argument, omit the next N records. If negative, +omit backwards." t nil) + +(autoload 'bbdb-refile-record "bbdb-com" "\ +Merge the current record into some other record; that is, delete the +record under point after copying all of the data within it into some other +record. this is useful if you realize that somehow a redundant record has +gotten into the database, and you want to merge it with another. + +If both records have names and/or companies, you are asked which to use. +Phone numbers, addresses, and network addresses are simply concatenated. +The first record is the record under the point; the second is prompted for. +Completion behaviour is as dictated by the variable `bbdb-completion-type'." t nil) + +(autoload 'bbdb-sort-notes "bbdb-com" "\ +Sort the notes in the record according to `bbdb-notes-sort-order'. +Can be used in `bbdb-change-hook'." nil nil) + +(autoload 'bbdb-sort-phones "bbdb-com" "\ +Sort the phones in the record according to the location. +Can be used in `bbdb-change-hook'." nil nil) + +(autoload 'bbdb-sort-addresses "bbdb-com" "\ +Sort the addresses in the record according to the location. +Can be used in `bbdb-change-hook'." nil nil) + +(autoload 'bbdb-dwim-net-address "bbdb-com" "\ +Returns a string to use as the email address of the given record. The +given address is the address the mail is destined to; this is formatted like +\"Firstname Lastname \" unless both the first name and last name are +constituents of the address, as in John.Doe@SomeHost, or the address is +already in the form \"Name \" or \"foo (Name)\", in which case the +address is used as-is. If `bbdb-dwim-net-address-allow-redundancy' is non-nil, +the name is always included. If `bbdb-dwim-net-address-allow-redundancy' is +'netonly the name is never included!" nil nil) + +(autoload 'bbdb-send-mail "bbdb-com" "\ +Compose a mail message to the person indicated by the current bbdb record. +The first (most-recently-added) address is used if there are more than one. +\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-send-mail]\" is used instead of simply \"\\[bbdb-send-mail]\", then mail will be sent to all of the +folks listed in the *BBDB* buffer instead of just the person at point." t nil) + +(autoload 'bbdb-show-all-recipients "bbdb-com" "\ +*Display BBDB records for all recipients of the message in this buffer." t nil) + +(autoload 'bbdb-completion-check-record "bbdb-com" nil nil nil) + +(autoload 'bbdb-completion-predicate "bbdb-com" "\ +For use as the third argument to `completing-read'. +Obey the semantics of `bbdb-completion-type'." nil nil) + +(autoload 'bbdb-read-addresses-with-completion "bbdb-com" "\ +Like `read-string', but allows `bbdb-complete-name' style completion." nil nil) + +(autoload 'bbdb-complete-name "bbdb-com" "\ +Complete the user full-name or net-address before point (up to the +preceeding newline, colon, or comma, or the value of START-POS). If +what has been typed is unique, insert an entry of the form \"User Name +\" (although see documentation for +bbdb-dwim-net-address-allow-redundancy). If it is a valid completion +but not unique, a list of completions is displayed. + +If the completion is done and `bbdb-complete-name-allow-cycling' is +true then cycle through the nets for the matching record. + +When called with a prefix arg then display a list of all nets. + +Completion behaviour can be controlled with `bbdb-completion-type'." t nil) + +(autoload 'bbdb-yank "bbdb-com" "\ +Insert the current contents of the *BBDB* buffer at point." t nil) + +(autoload 'bbdb-define-all-aliases "bbdb-com" "\ +Define mail aliases for some of the records in the database. +Every record which has a `mail-alias' field will have a mail alias +defined for it which is the contents of that field. If there are +multiple comma-separated words in the `mail-alias' field, then all +of those words will be defined as aliases for that person. + +If multiple entries in the database have the same mail alias, then +that alias expands to a comma-separated list of the network addresses +of all of those people." t nil) + +(autoload 'bbdb-add-or-remove-mail-alias "bbdb-com" "\ +Add NEWALIAS in all RECORDS or remove it if DELETE it t. +When called with prefix argument it will remove the alias. +We honor `bbdb-apply-next-command-to-all-records'! +The new alias will only be added if it isn't there yet." t nil) + +(autoload 'bbdb-dial "bbdb-com" "\ +Dial the number at point. +If the point is at the beginning of a record, dial the first +phone number. Does not dial the extension. Does not apply the +transformations from bbdb-dial-local-prefix-alist if a prefix arg +is given." t nil) + +(autoload 'bbdb-finger "bbdb-com" "\ +Finger the network address of a BBDB record. +If this command is executed from the *BBDB* buffer, finger the network +address of the record at point; otherwise, it prompts for a user. +With a numeric prefix argument, finger the Nth network address of the +current record; with a prefix argument of ^U, finger all of them. +The *finger* buffer is filled asynchronously, meaning that you don't +have to wait around for it to finish; but fingering another user before +the first finger has finished could have unpredictable results. +\\ +If this command is executed from the *BBDB* buffer, it may be prefixed +with \"\\[bbdb-apply-next-command-to-all-records]\" (as in \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-finger]\" instead of simply \"\\[bbdb-finger]\"), meaning to finger all of +the users currently listed in the *BBDB* buffer instead of just the one +at point. The numeric prefix argument has the same interpretation. + +You can define a special network address to \"finger\" by defining a +field `finger-host' (default value of `bbdb-finger-host-field')." t nil) + +(autoload 'bbdb-timestamp-older "bbdb-com" "\ +*Display records with timestamp older than DATE. +DATE must be in yyyy-mm-dd format." t nil) + +(autoload 'bbdb-timestamp-newer "bbdb-com" "\ +*Display records with timestamp newer than DATE. +DATE must be in yyyy-mm-dd format." t nil) + +(autoload 'bbdb-creation-older "bbdb-com" "\ +*Display records with creation-date older than DATE. +DATE must be in yyyy-mm-dd format." t nil) + +(autoload 'bbdb-creation-newer "bbdb-com" "\ +*Display records with creation-date newer than DATE. +DATE must be in yyyy-mm-dd format." t nil) + +(autoload 'bbdb-creation-no-change "bbdb-com" "\ +*Display records that have the same timestamp and creation-date." t nil) + +(autoload 'bbdb-info "bbdb-com" nil t nil) + +(autoload 'bbdb-help "bbdb-com" nil t nil) + +(defcustom bbdb-update-records-mode 'annotating "Controls how `bbdb-update-records' processes email addresses.\nSet this to an expression which evaluates either to 'searching or\n'annotating. When set to 'annotating email addresses will be fed to\n`bbdb-annotate-message-sender' in order to update existing records or create\nnew ones. A value of 'searching will search just for existing records having\nthe right net.\n\nThere is a version of this variable for each MUA, which overrides this variable\nwhen set!\n\nThis variable is also used for inter-function communication between the\nfunctions `bbdb-update-records' and `bbdb-prompt-for-create'." :group 'bbdb-mua-specific :type '(choice (const :tag "annotating all messages" annotating) (const :tag "annotating no messages" searching) (sexp :tag "user defined"))) + +(autoload 'bbdb-update-records "bbdb-com" "\ +Returns the records corresponding to the list of addresses ADDRS, +creating or modifying them as necessary. A record will be created if +AUTO-CREATE-P is non-nil or if OFFER-TO-CREATE is true and the user +confirms the creation. + +The variable `bbdb/gnus-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked any more for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." nil nil) + +(defcustom bbdb-get-addresses-headers '((authors "From" "Resent-From" "Reply-To") (recipients "Resent-To" "Resent-CC" "To" "CC" "BCC")) "*List of headers to search for senders and recipients email addresses.\nThe headers are grouped into two classes, the authors and the senders headers." :group 'bbdb-mua-specific :type 'list) + +(defcustom bbdb-get-only-first-address-p t "*If t `bbdb-update-records' will return only the first one.\nChanging this variable will show its effect only after clearing the\n`bbdb-message-cache' of a folder or closing and visiting it again." :group 'bbdb-mua-specific :type 'boolean) + +;;;*** + +;;;### (autoloads (bbdb-create-ftp-site bbdb-ftp) "bbdb-ftp" "lisp/bbdb-ftp.el") + +(autoload 'bbdb-ftp "bbdb-ftp" "\ +Use ange-ftp to open an ftp-connection to a BBDB record's name. +If this command is executed from the *BBDB* buffer, ftp the site of +the record at point; otherwise, it prompts for an ftp-site." t nil) + +(autoload 'bbdb-create-ftp-site "bbdb-ftp" "\ +Add a new ftp-site entry to the bbdb database. +Prompts for all relevant info using the echo area, +inserts the new record in the db, sorted alphabetically." t nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-gnus bbdb/gnus-summary-show-all-recipients bbdb/gnus-score bbdb/gnus-snarf-signature bbdb/gnus-show-all-recipients bbdb/gnus-show-records bbdb/gnus-annotate-sender bbdb/gnus-update-records bbdb/gnus-update-record) "bbdb-gnus" "lisp/bbdb-gnus.el") + +(autoload 'bbdb/gnus-update-record "bbdb-gnus" "\ +Return the record corresponding to the current GNUS message, creating +or modifying it as necessary. A record will be created if +bbdb/news-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." nil nil) + +(autoload 'bbdb/gnus-update-records "bbdb-gnus" "\ +Return the records corresponding to the current GNUS message, creating +or modifying it as necessary. A record will be created if +bbdb/news-auto-create-p is non-nil or if OFFER-TO-CREATE is true +and the user confirms the creation. + +The variable `bbdb/gnus-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked anymore for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." nil nil) + +(autoload 'bbdb/gnus-annotate-sender "bbdb-gnus" "\ +Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." t nil) + +(autoload 'bbdb/gnus-show-records "bbdb-gnus" "\ +Display the contents of the BBDB for all addresses of this message. +This buffer will be in `bbdb-mode', with associated keybindings." t nil) + +(autoload 'bbdb/gnus-show-all-recipients "bbdb-gnus" "\ +Show all recipients of this message. Counterpart to `bbdb/vm-show-sender'." t nil) + +(autoload 'bbdb/gnus-snarf-signature "bbdb-gnus" "\ +Snarf signature from the corresponding *Article* buffer." t nil) + +(autoload 'bbdb/gnus-score "bbdb-gnus" "\ +This returns a score alist for GNUS. A score pair will be made for +every member of the net field in records which also have a gnus-score +field. This allows the BBDB to serve as a supplemental global score +file, with the advantage that it can keep up with multiple and changing +addresses better than the traditionally static global scorefile." nil nil) + +(autoload 'bbdb/gnus-summary-show-all-recipients "bbdb-gnus" "\ +Display BBDB records for all recipients of the message." t nil) + +(autoload 'bbdb-insinuate-gnus "bbdb-gnus" "\ +Call this function to hook BBDB into GNUS." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-menu bbdb-fontify-buffer) "bbdb-gui" "lisp/bbdb-gui.el") + +(autoload 'bbdb-fontify-buffer "bbdb-gui" nil t nil) + +(autoload 'bbdb-menu "bbdb-gui" nil t nil) + +;;;*** + +;;;### (autoloads (bbdb-force-record-create sample-bbdb-canonicalize-net-hook bbdb-auto-notes-hook bbdb-ignore-some-messages-hook bbdb-ignore-selected-messages-hook bbdb-ignore-most-messages-hook bbdb-extract-field-value bbdb-header-start bbdb-creation-date-hook bbdb-timestamp-hook) "bbdb-hooks" "lisp/bbdb-hooks.el") + +(autoload 'bbdb-timestamp-hook "bbdb-hooks" "\ +For use as a `bbdb-change-hook'; maintains a notes-field called `timestamp' +for the given record which contains the time when it was last modified. If +there is such a field there already, it is changed, otherwise it is added." nil nil) + +(autoload 'bbdb-creation-date-hook "bbdb-hooks" "\ +For use as a `bbdb-create-hook'; adds a notes-field called `creation-date' +which is the current time string." nil nil) + +(autoload 'bbdb-header-start "bbdb-hooks" "\ +Returns a marker at the beginning of the header block of the current +message. This will not necessarily be in the current buffer." nil nil) + +(autoload 'bbdb-extract-field-value "bbdb-hooks" "\ +Given the name of a field (like \"Subject\") this returns the value of +that field in the current message, or nil. This works whether you're in +GNUS, Rmail, or VM. This works on multi-line fields, but if more than +one field of the same name is present, only the last is returned. It is +expected that the current buffer has a message in it, and (point) is at the +beginning of the message headers." nil nil) + +(autoload 'bbdb-ignore-most-messages-hook "bbdb-hooks" "\ +For use as the value of bbdb/news-auto-create-p or bbdb/mail-auto-create-p. +This will automatically create BBDB entries for messages which match +the bbdb-ignore-most-messages-alist (which see) and *no* others." nil nil) + +(autoload 'bbdb-ignore-selected-messages-hook "bbdb-hooks" "\ +For use as a bbdb/news-auto-create-hook or bbdb/mail-auto-create-hook. +This will automatically create BBDB entries for messages based on a +combination of bbdb-ignore-some-messages-alist and +bbdb-ignore-most-messages-alist. It first looks at the SOME list. If +that doesn't disqualify a message, then it looks at the MOST list. If +that qualifies the message, the record is auto-created, but a +confirmation is conditionally sought, based on the value of +`bbdb-ignore-selected-messages-confirmation'." nil nil) + +(autoload 'bbdb-ignore-some-messages-hook "bbdb-hooks" "\ +For use as a `bbdb/news-auto-create-hook' or `bbdb/mail-auto-create-hook'. +This will automatically create BBDB entries for messages which do *not* +match the `bbdb-ignore-some-messages-alist' (which see)." nil nil) + +(autoload 'bbdb-auto-notes-hook "bbdb-hooks" "\ +For use as a `bbdb-notice-hook'. This might automatically add some text +to the notes field of the BBDB record corresponding to the current record +based on the header of the current message. See the documentation for +the variables `bbdb-auto-notes-alist' and `bbdb-auto-notes-ignore'." nil nil) + +(autoload 'sample-bbdb-canonicalize-net-hook "bbdb-hooks" nil nil nil) + +(autoload 'bbdb-force-record-create "bbdb-hooks" "\ +Force automatic creation of a BBDB records for the current message. +You might add this to the reply hook of your MUA in order to automatically +get records added for those people you reply to." t nil) + +;;;*** + +;;;### (autoloads (bbdb-merge-file bbdb-merge-record) "bbdb-merge" "lisp/bbdb-merge.el") + +(autoload 'bbdb-merge-record "bbdb-merge" "\ +Generic merge function. + +Merges new-record into your bbdb, using DATE to check who's more +up-to-date and OVERRIDE to decide who gets precedence if two dates +match. DATE can be extracted from a notes if it's an alist with an +element marked timestamp. Set OVERRIDE to 'new to allow the new record +to stomp on existing data, 'old to preserve existing data or nil to +merge both together. If it can't find a record to merge with, it will +create a new record. If MERGE-RECORD is set, it's a record discovered +by other means that should be merged with. + +Returns the Grand Unified Record." nil nil) + +(autoload 'bbdb-merge-file "bbdb-merge" "\ +Merge a bbdb file into the in-core bbdb." t nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-mh bbdb/mh-show-sender bbdb/mh-annotate-sender bbdb/mh-update-record) "bbdb-mhe" "lisp/bbdb-mhe.el") + +(autoload 'bbdb/mh-update-record "bbdb-mhe" "\ +Returns the record corresponding to the current MH message, creating or +modifying it as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." nil nil) + +(autoload 'bbdb/mh-annotate-sender "bbdb-mhe" "\ +Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." t nil) + +(autoload 'bbdb/mh-show-sender "bbdb-mhe" "\ +Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." t nil) + +(autoload 'bbdb-insinuate-mh "bbdb-mhe" "\ +Call this function to hook BBDB into MH-E." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-migrate-update-file-version bbdb-migrate-rewrite-all bbdb-unmigrate-record bbdb-migrate bbdb-migration-query) "bbdb-migrate" "lisp/bbdb-migrate.el") + +(autoload 'bbdb-migration-query "bbdb-migrate" "\ +Ask if the database is to be migrated. +ONDISK is the version number of the database as currently stored on +disk. Returns the version for the saved database." nil nil) + +(autoload 'bbdb-migrate "bbdb-migrate" "\ +Migrate the BBDB from the version on disk (the car of +`bbdb-file-format-migration') to the current version (in +`bbdb-file-format')." nil nil) + +(autoload 'bbdb-unmigrate-record "bbdb-migrate" "\ +Reverse-migrate a single record from the current version (in +`bbdb-file-format') to the version to be saved (the cdr of +`bbdb-file-format-migration')." nil nil) + +(autoload 'bbdb-migrate-rewrite-all "bbdb-migrate" "\ +Rewrite each and every record in the bbdb file; this is necessary if we +are updating an old file format. MESSAGE-P says whether to sound off +for each record converted. If RECORDS is non-nil, its value will be +used as the list of records to update." nil nil) + +(autoload 'bbdb-migrate-update-file-version "bbdb-migrate" "\ +Change the `file-version' string from the OLD version to the NEW +version." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-print) "bbdb-print" "lisp/bbdb-print.el") + +(autoload 'bbdb-print "bbdb-print" "\ +Make a TeX file for printing out the bbdb database.\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-print]\" is used instead of simply \"\\[bbdb-print]\", then includes only the +people currently in the *BBDB* buffer. With a prefix argument, makes +a brief (one-line-per-entry) printout. + +There are various variables for customizing the content & format of +the printout, notably the variables `bbdb-print-alist' and +`bbdb-print-require'. See the file bbdb-print.el for more information." t nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-reportmail) "bbdb-reportmail" "lisp/bbdb-reportmail.el") + +(autoload 'bbdb-insinuate-reportmail "bbdb-reportmail" "\ +Call this function to hook BBDB into reportmail." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-rmail bbdb/rmail-show-sender bbdb/rmail-annotate-sender bbdb/rmail-update-record) "bbdb-rmail" "lisp/bbdb-rmail.el") + +(autoload 'bbdb/rmail-update-record "bbdb-rmail" nil nil nil) + +(autoload 'bbdb/rmail-annotate-sender "bbdb-rmail" "\ +Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." t nil) + +(autoload 'bbdb/rmail-show-sender "bbdb-rmail" "\ +Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." t nil) + +(autoload 'bbdb-insinuate-rmail "bbdb-rmail" "\ +Call this function to hook BBDB into RMAIL." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-sc bbdb/sc-default) "bbdb-sc" "lisp/bbdb-sc.el") + +(autoload 'bbdb/sc-default "bbdb-sc" "\ +If the current \"from\" field in `sc-mail-info' alist +contains only an e-mail address, lookup e-mail address in +BBDB, and prepend a new \"from\" field to `sc-mail-info'." nil nil) + +(autoload 'bbdb-insinuate-sc "bbdb-sc" "\ +Call this function to hook BBDB into Supercite." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-rfc822-addresses bbdb-extract-address-components bbdb-snarf-region bbdb-snarf) "bbdb-snarf" "lisp/bbdb-snarf.el") + +(autoload 'bbdb-snarf "bbdb-snarf" "\ +snarf up a bbdb record WHERE the point is. +We assume things are line-broken and paragraph-bounded. +The name comes first and other fields (address, +phone, email, web pages) are recognized by context. + +Required context: + addresses end with \"City, State ZIP\" or \"City, State\" + phones match bbdb-snarf-phone-regexp + (currently US-style phones) + e-mail addresses have @'s in them + web sites are recognized by http:// or www. + +Address and phone context are currently US-specific; +patches to internationalize these assumptions are welcome. + +\\[bbdb-snarf] is similar to \\[bbdb-whois-sentinel], but less specialized." t nil) + +(autoload 'bbdb-snarf-region "bbdb-snarf" "\ +snarf up a bbdb record in the current region. See `bbdb-snarf' for +more details." t nil) + +(autoload 'bbdb-extract-address-components "bbdb-snarf" "\ +Return a list of address components found in ADSTRING. +If extracting fails one probably has to adjust the variable +`bbdb-extract-address-component-regexps'." nil nil) + +(autoload 'bbdb-rfc822-addresses "bbdb-snarf" "\ +Split ADDRLINE into a list of parsed addresses. + +You can't do this with rfc822.el in any sort of useful way because it discards +the comments. You can't do this with mail-extr.el because the multiple address +parsing in GNU Emacs appears to be broken beyond belief, and the XEmacs +version doesn't support multiple addresses." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-srv-add-phone bbdb/srv-auto-create-mail-news-dispatcher bbdb/srv-handle-headers-with-delay) "bbdb-srv" "lisp/bbdb-srv.el") + +(autoload 'bbdb/srv-handle-headers-with-delay "bbdb-srv" "\ +Just like bbdb/srv-handle-headers, but only updates every few seconds. +This is so that trying to display many records in succession won't queue them +up, but will end up only displaying a record when no displays have been +requested for a couple of seconds." nil nil) + +(defalias 'bbdb-srv 'bbdb/srv-handle-headers-with-delay) + +(autoload 'bbdb/srv-auto-create-mail-news-dispatcher "bbdb-srv" "\ +For use as the value of bbdb/srv-auto-create-p. +This will try to decide if this is a mail message or a news message, and then +run either bbdb/news-auto-create-p or bbdb/mail-auto-create-p as appropriate. +\(The heuristic is that news messages never have a Status or X-Mozilla-Status +header; and that mail messages never have Path headers.)" nil nil) + +(autoload 'bbdb-srv-add-phone "bbdb-srv" nil nil nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-vm bbdb/vm-set-auto-folder-alist bbdb/vm-show-sender bbdb/vm-show-all-recipients bbdb/vm-show-records bbdb/vm-annotate-sender bbdb/vm-update-records bbdb/vm-update-record) "bbdb-vm" "lisp/bbdb-vm.el") + +(autoload 'bbdb/vm-update-record "bbdb-vm" nil nil nil) + +(autoload 'bbdb/vm-update-records "bbdb-vm" "\ +Returns the records corresponding to the current VM message, +creating or modifying them as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil or if OFFER-TO-CREATE is true, and +the user confirms the creation. + +The variable `bbdb/vm-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked anymore for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." nil nil) + +(autoload 'bbdb/vm-annotate-sender "bbdb-vm" "\ +Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." t nil) + +(autoload 'bbdb/vm-show-records "bbdb-vm" "\ +Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." t nil) + +(autoload 'bbdb/vm-show-all-recipients "bbdb-vm" "\ +Show all recipients of this message. Counterpart to `bbdb/vm-show-sender'." t nil) + +(autoload 'bbdb/vm-show-sender "bbdb-vm" "\ +Display the contents of the BBDB for the senders of this message. +With a prefix argument show the recipients instead, +with two prefix arguments show all records. +This buffer will be in `bbdb-mode', with associated keybindings." t nil) + +(defcustom bbdb/vm-set-auto-folder-alist-field 'vm-folder "*The field which `bbdb/vm-set-auto-folder-alist' searches for." :group 'bbdb-mua-specific-vm :type 'symbol) + +(defcustom bbdb/vm-set-auto-folder-alist-headers '("From:" "To:" "CC:") "*The headers used by `bbdb/vm-set-auto-folder-alist'.\nThe order in this list is the order how matching will be performed!" :group 'bbdb-mua-specific-vm :type '(repeat (string :tag "header name"))) + +(autoload 'bbdb/vm-set-auto-folder-alist "bbdb-vm" "\ +Create a `vm-auto-folder-alist' according to the records in the bbdb. +For each record that has a 'vm-folder' attribute, add an +element (email-regexp . folder) to the `vm-auto-folder-alist'. + +The element gets added to the 'element-name' sublist of the +`vm-auto-folder-alist'. + +The car of the element consists of all the email addresses for the +bbdb record concatenated with OR; the cdr is the value of the +vm-folder attribute. + +If the first character of vm-folders value is a quote ' it will be +parsed as lisp expression and is evaluated to return a folder name, +e.g. define you own function `my-folder-name' and set it to + '(my-folder-name)" t nil) + +(autoload 'bbdb-insinuate-vm "bbdb-vm" "\ +Call this function to hook BBDB into VM." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-w3 bbdb-www-grab-homepage bbdb-www) "bbdb-w3" "lisp/bbdb-w3.el") + +(autoload 'bbdb-www "bbdb-w3" "\ +Visit URLs stored in the `www' field of the current record. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-www] means to try all records currently visible. +Non-interactively, do all records if arg is nonnil." t nil) + +(autoload 'bbdb-www-grab-homepage "bbdb-w3" "\ +Grab the current URL and store it in the bbdb database" t nil) + +(autoload 'bbdb-insinuate-w3 "bbdb-w3" "\ +Call this function to hook BBDB into W3." nil nil) + +;;;*** + +;;;### (autoloads (bbdb-whois) "bbdb-whois" "lisp/bbdb-whois.el") + +(autoload 'bbdb-whois "bbdb-whois" nil t nil) + +;;;*** + +;;;### (autoloads (bbdb-load-touchtones bbdb-xemacs-display-completion-list) "bbdb-xemacs" "lisp/bbdb-xemacs.el") + +(autoload 'bbdb-xemacs-display-completion-list "bbdb-xemacs" "\ +Wrapper for `display-completion-list'. +Allows callbacks on XEmacs `display-completion-list' is called with +`:activate-callback CALLBACK' if CALLBACK is non-nil. +`:user-data DATA' is also used if DATA is non-nil. +Neither are used if CALLBACK is nil." nil nil) + +(defcustom bbdb-sounds-directory (expand-file-name "~/.xemacs/etc/sounds") "The directory to load the touchtone sound files from, or nil if none." :group 'bbdb-phone-dialing :type 'directory) + +(defcustom bbdb-sound-volume 50 "Volume for playing sounds." :group 'bbdb-phone-dialing :type 'integer) + +(autoload 'bbdb-load-touchtones "bbdb-xemacs" "\ +Load the touchtone sounds into `sound-alist'. +The directory specified in `bbdb-sounds-directory' is searched for the files +touchtone.*\\.\\(wav\\|au\\) as named in `bbdb-sound-files'. +They are stored in `sound-alist' as touchtone0 to touchtone11." t nil) + +;;;*** + +;;;### (autoloads (bbdb-insinuate-message bbdb-initialize bbdb-submit-bug-report) "bbdb" "lisp/bbdb.el") + +(autoload 'bbdb-submit-bug-report "bbdb" "\ +Submit a bug report, with pertinent information to the BBDB info list." t nil) + +(defcustom bbdb-multiple-buffers nil "When non-nil we create a new buffer of every buffer causing pop-ups.\nYou can also set this to a function returning a buffer name." :group 'bbdb-record-display :type '(choice (const :tag "Disabled" nil) (function :tag "Enabled" bbdb-multiple-buffers-default) (function :tag "User defined function"))) + +(autoload 'bbdb-initialize "bbdb" "\ +*Initialize the BBDB. One or more of the following symbols can be +passed as arguments to initiate the appropriate insinuations. + + Initialization of mail/news readers: + + gnus Initialize BBDB support for the gnus mail/news reader + version 3.15 or newer. If you pass the `gnus' symbol, + you should probably also pass the `message' symbol. + mh-e Initialize BBDB support for the MH-E mail reader. + rmail Initialize BBDB support for the RMAIL mail reader. + sendmail Initialize BBDB support for sendmail (M-x mail). + vm Initialize BBDB support for the VM mail reader. + NOTE: For the VM insinuation to work properly, you must + either call `bbdb-initialize' with the `vm' symbol from + within your VM initialization file (\"~/.vm\") or you + must call `bbdb-insinuate-vm' manually from within your + VM initialization file. + + Initialization of miscellaneous package: + + message Initialize BBDB support for Message mode. + reportmail Initialize BBDB support for the Reportmail mail + notification package. + sc or Initialize BBDB support for the Supercite message + supercite citation package. + w3 Initialize BBDB support for Web browsers." nil nil) + +(autoload 'bbdb-insinuate-message "bbdb" "\ +Call this function to hook BBDB into `message-mode'." nil nil) + +;;;*** + +(provide 'bbdb-autoloads) diff --git a/xemacs-packages/lisp/bbdb/auto-autoloads.elc b/xemacs-packages/lisp/bbdb/auto-autoloads.elc new file mode 100644 index 0000000000000000000000000000000000000000..41529da54b87d3404a022e389798b7772ff5290b GIT binary patch literal 35864 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 Bkb?jK literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-com.el b/xemacs-packages/lisp/bbdb/bbdb-com.el new file mode 100644 index 00000000..0088712c --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-com.el @@ -0,0 +1,3612 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file is part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992, 1993 Jamie Zawinski . +;;; It contains most of the user-level interactive commands for BBDB. +;;; See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-com.el,v 1.9 2005/07/24 15:22:57 waider Exp $ +;; + +(require 'bbdb) +;;(require 'bbdb-snarf) causes recursive compile! +(eval-when-compile + (require 'cl) + (defvar bbdb-extract-address-components-func)) ;; bbdb-snarf + +;; ARGH. fmh, dammit. +(require + (eval-and-compile + (if (locate-library "mailabbrev") + (quote mailabbrev) + (quote mail-abbrevs)))) + +;; compiler placating. +;; not sure BBDB runs on anything old enough to use auto-fill-hook, mind. +(eval-and-compile + (if (boundp 'auto-fill-function) + (fset 'bbdb-auto-fill-function 'auto-fill-function) + (fset 'bbdb-auto-fill-function 'auto-fill-hook)) + + (autoload 'mh-send "mh-e") + (autoload 'vm-session-initialization "vm-startup") + (autoload 'vm-mail-internal "vm-reply") + (autoload 'mew-send "mew") + (autoload 'bbdb-header-start "bbdb-hooks") + (autoload 'bbdb-extract-field-value "bbdb-hooks") + (autoload 'bbdb-fontify-buffer "bbdb-gui") + (autoload 'Info-goto-node "info") + ;; this is very unpleasant, but saves me doing a lot of rewriting + ;; for now. a big cleanup will happen for the next release, maybe. + ;; NB if emacs 21 or older emacsen or even things you bolt on have + ;; any of these functions, bad things will happen. Again, FITNR. + (if (featurep 'xemacs) + (progn + (fset 'bbdb-extent-string 'extent-string) + (fset 'bbdb-display-message 'display-message) + (fset 'bbdb-event-to-character 'event-to-character)) + (fset 'bbdb-extent-string 'ignore) + (fset 'bbdb-display-message 'ignore) + (fset 'bbdb-event-to-character 'ignore))) + +(defvar bbdb-define-all-aliases-needs-rebuilt nil) + +(defcustom bbdb-default-country + '"Emacs";; what do you mean, it's not a country? + "*Default country to use if none is specified." + :group 'bbdb-record-creation + :type 'string) ;; wonder if there's a smart place to get this? TZ, maybe? + +(defmacro bbdb-grovel-elide-arg (arg) + (list 'if arg + (list 'not (list 'eq arg 0)) + 'bbdb-display-layout)) + +(defvar bbdb-search-invert nil + "Bind this variable to t in order to invert the result of `bbdb-search'. + +\(let ((bbdb-search-invert t)) + \(bbdb-search records foo foo))") + +(defun bbdb-search-invert-p () + "Return `bbdb-search-invert' and set it to nil. +To set it on again, use `bbdb-search-invert-set'." + (let ((result bbdb-search-invert)) + (setq bbdb-search-invert nil) + result)) + +;;;###autoload +(defun bbdb-search-invert-set () + "Typing \\\\[bbdb-search-invert-set] inverts the meaning of the next search command. +Sets `bbdb-search-invert' to t. +You will have to call this function again, if you want to +do repeated inverted searches." + (interactive) + (setq bbdb-search-invert t) + (message (substitute-command-keys + "\\\\[bbdb-search-invert-set] - "))) + +(defmacro bbdb-search (records &optional name company net notes phone) + "Search RECORDS for optional arguments NAME, COMPANY, NET, NOTES, PHONE. +This macro only emits code for those things being searched for; +literal nils at compile-time cause no code to be emitted. + +If you want to reverse the search, bind `bbdb-search-invert' to t." + (let (clauses) + ;; I didn't protect these vars from multiple evaluation because that + ;; actually generates *less efficient code* in elisp, because the extra + ;; bindings can't easily be optimized away without lexical scope. fmh. + (or (stringp name) (symbolp name) (error "name must be atomic")) + (or (stringp company) (symbolp company) (error "company must be atomic")) + (or (stringp net) (symbolp net) (error "net must be atomic")) + (or (stringp notes) (symbolp notes) (error "notes must be atomic")) + (or (stringp phone) (symbolp phone) (error "phone must be atomic")) + (if phone + (setq clauses + (cons + (` (let ((rest-of-phones (bbdb-record-phones record)) + (done nil)) + (if rest-of-phones + (while (and rest-of-phones (not done)) + (setq done (string-match (, phone) + ;; way way wasteful... + (bbdb-phone-string + (car rest-of-phones))) + rest-of-phones (cdr rest-of-phones))) + ;; so that "^$" can be used to find entries that + ;; have no phones + (setq done (string-match (, phone) ""))) + done)) + clauses))) + (if notes + (setq clauses + (cons + (` (if (stringp (, notes)) + (string-match (, notes) + (or (bbdb-record-notes record) "")) + (if (eq (car (, notes)) '*) + (let ((fields all-fields) done tmp) + (if (bbdb-record-raw-notes record) + (while (and (not done) fields) + (setq tmp (bbdb-record-getprop + record (car fields)) + done (and tmp (string-match + (cdr (, notes)) + tmp)) + fields (cdr fields))) + ;; so that "^$" can be used to find entries that + ;; have no notes + (setq done (string-match (cdr (, notes)) ""))) + done) + (string-match (cdr (, notes)) + (or (bbdb-record-getprop + record (car (, notes))) ""))))) + clauses))) + (if name + (setq clauses + (append + (` ((string-match (, name) (or (bbdb-record-name record) "")) + (let ((rest-of-aka (bbdb-record-aka record)) + (done nil)) + (while (and rest-of-aka (not done)) + (setq done (string-match (, name) (car rest-of-aka)) + rest-of-aka (cdr rest-of-aka))) + done))) + clauses))) + (if net + (setq clauses + (cons + (` (let ((rest-of-nets (bbdb-record-net record)) + (done nil)) + (if rest-of-nets + (while (and rest-of-nets (not done)) + (setq done (string-match (, net) (car rest-of-nets)) + rest-of-nets (cdr rest-of-nets))) + ;; so that "^$" can be used to find entries that + ;; have no net addresses. + (setq done (string-match (, net) ""))) + done)) + clauses))) + (if company + (setq clauses + (cons + (` (string-match (, company) + (or (bbdb-record-company record) ""))) + clauses))) + + (` (let ((matches '()) + (,@ (if notes + '((all-fields (cons 'notes + (mapcar (lambda (x) (intern (car x))) + (bbdb-propnames))))) + nil)) + (case-fold-search bbdb-case-fold-search) + (records (, records)) + (invert (bbdb-search-invert-p)) + record) + (while records + (setq record (car records)) + (if (or (and invert + (not (or (,@ clauses)))) + (and (not invert) + (or (,@ clauses)))) + (setq matches (cons record matches))) + (setq records (cdr records))) + (nreverse matches))))) + +(defun bbdb-search-prompt (prompt &rest rest) + (if (string-match "%m" prompt) + (setq prompt (replace-match (if bbdb-search-invert + "not matching" + "matching") + nil nil prompt))) + (read-string (apply 'format prompt rest))) + +;;;###autoload +(defun bbdb (string elidep) + "Display all entries in the BBDB matching the regexp STRING +in either the name(s), company, network address, or notes." + (interactive + (list (bbdb-search-prompt "Search records %m regexp: ") + current-prefix-arg)) + (let* ((bbdb-display-layout (bbdb-grovel-elide-arg elidep)) + (notes (cons '* string)) + (records + (bbdb-search (bbdb-records) string string string notes + nil))) + (if records + (bbdb-display-records records) + ;; we could use error here, but it's not really an error. + (message "No records matching '%s'" string)))) + +;;;###autoload +(defun bbdb-name (string elidep) + "Display all entries in the BBDB matching the regexp STRING in the name +\(or ``alternate'' names\)." + (interactive + (list (bbdb-search-prompt "Search records with names %m regexp: ") + current-prefix-arg)) + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep))) + (bbdb-display-records (bbdb-search (bbdb-records) string)))) + +;;;###autoload +(defun bbdb-company (string elidep) + "Display all entries in BBDB matching STRING in the company field." + (interactive + (list (bbdb-search-prompt "Search records with company %m regexp: ") + current-prefix-arg)) + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep))) + (bbdb-display-records (bbdb-search (bbdb-records) nil string)))) + +;;;###autoload +(defun bbdb-net (string elidep) + "Display all entries in BBDB matching regexp STRING in the network address." + (interactive + (list (bbdb-search-prompt "Search records with net address %m regexp: ") + current-prefix-arg)) + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep))) + (bbdb-display-records (bbdb-search (bbdb-records) nil nil string)))) + +;;;###autoload +(defun bbdb-notes (which string elidep) + "Display all entries in BBDB matching STRING in the named notes field." + (interactive + (let (field) + (list (setq field (completing-read "Notes field to search (RET for all): " + (append '(("notes")) (bbdb-propnames)) + nil t)) + (if (featurep 'gmhist) + (read-with-history-in 'bbdb-notes-field "Regular expression: ") + (bbdb-search-prompt "Search records with %s %m regexp: " + (if (string= field "") + "one field" + field))) + current-prefix-arg))) + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep)) + (notes (if (string= which "") + (cons '* string) + (cons (intern which) string)))) + (bbdb-display-records (bbdb-search (bbdb-records) nil nil nil notes)))) + +(defun bbdb-phones (string elidep) + "Display all entries in BBDB matching the regexp STRING in the phones field." + (interactive + (list (bbdb-search-prompt "Search records with phone %m regexp: ") + current-prefix-arg)) + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep))) + (bbdb-display-records + (bbdb-search (bbdb-records) nil nil nil nil string)))) + +;;;###autoload +(defun bbdb-changed (elidep) + "Display all entries in the bbdb database which have been changed since +the database was last saved." + (interactive "P") + (let ((bbdb-display-layout (bbdb-grovel-elide-arg elidep)) + (changed-records (bbdb-with-db-buffer bbdb-changed-records))) + (if (bbdb-search-invert-p) + (let ((recs (bbdb-records)) + unchanged-records + r) + (while recs + (setq r (car recs) + recs (cdr recs)) + (when (not (member r changed-records)) + (setq changed-records (delete r changed-records) + unchanged-records (cons r unchanged-records)))) + (bbdb-display-records unchanged-records)) + (bbdb-display-records changed-records)))) + +(defun bbdb-display (records) + "Prompts for and displays a single record (this is faster than searching.)" + (interactive (list (bbdb-completing-read-record "Display record of: "))) + (bbdb-display-records records)) + +(defun bbdb-display-some (function) + "Display records according to FUNCTION. FUNCTION is called with one +argument, the record, and should return nil if the record is not to be +displayed. If the record is to be displayed, it (the record) should +be returned." + (bbdb-display-records (delq nil (mapcar function (bbdb-records))))) + +;;; fancy redisplay + +;;;###autoload +(defun bbdb-redisplay-records () + "Regrinds the contents of the *BBDB* buffer, without scrolling. +If possible, you should call `bbdb-redisplay-one-record' instead." + (let ((p (point)) + (m (condition-case nil (mark) (error nil)))) + (goto-char (window-start)) + (let ((p2 (point))) + (bbdb-display-records-1 bbdb-records) + (goto-char p2) + (if m (set-mark m))) + (recenter 0) + (goto-char p) + (save-excursion + (run-hooks 'bbdb-list-hook)))) + +(defun bbdb-redisplay-one-record (record &optional record-cons next-record-cons + delete-p) + "Regrind one record. The *BBDB* buffer must be current when this is called." + (bbdb-debug (if (not (eq (not (not delete-p)) + (not (not (bbdb-record-deleted-p record))))) + (error "splorch."))) + (if (null record-cons) (setq record-cons (assq record bbdb-records))) + (if (null next-record-cons) + (setq next-record-cons (car (cdr (memq record-cons bbdb-records))))) + (if (null record-cons) + (bbdb-display-records (list record) nil t) + (let ((position (point)) + (marker (nth 2 record-cons)) + next-marker + (buffer-read-only nil)) + (bbdb-debug + (if (null record-cons) (error "doubleplus ungood: record unexists!")) + (if (null marker) (error "doubleplus ungood: marker unexists!"))) + (beginning-of-line) + (goto-char marker) + (remove-text-properties marker (or (nth 2 next-record-cons) (point-max)) + '(bbdb-field nil)) + (if delete-p nil + (bbdb-format-record (car record-cons) (car (cdr record-cons)))) + (setq next-marker (or (nth 2 next-record-cons) (point-max))) + (delete-region (point) next-marker) + (if (< position next-marker) + (goto-char position)) + + (if (and bbdb-gui (not delete-p)) + (bbdb-fontify-buffer (list record-cons + ;; the record ends here + (list nil nil next-marker)))) + (save-excursion + (run-hooks 'bbdb-list-hook))))) + +;;; Parsing phone numbers +;;; XXX this needs expansion to handle international prefixes properly +;;; i.e. +353-number without discarding the +353 part. Problem being +;;; that this will necessitate yet another change in the database +;;; format for people who are using north american numbers. + + +(defconst bbdb-phone-area-regexp "(?[ \t]*\\+?1?[ \t]*[-\(]?[ \t]*[-\(]?[ \t]*\\([2-9][0-9][0-9]\\)[ \t]*)?[-./ \t]*") +(defconst bbdb-phone-main-regexp "\\([1-9][0-9][0-9]\\)[ \t]*[-.]?[ \t]*\\([0-9][0-9][0-9][0-9]\\)[ \t]*") + +(defconst bbdb-phone-ext-regexp "x?[ \t]*\\([0-9]+\\)[ \t]*") + +(defconst bbdb-phone-regexp-1 (concat "^[ \t]*" bbdb-phone-area-regexp bbdb-phone-main-regexp bbdb-phone-ext-regexp "$")) +(defconst bbdb-phone-regexp-2 (concat "^[ \t]*" bbdb-phone-area-regexp bbdb-phone-main-regexp "$")) +(defconst bbdb-phone-regexp-3 (concat "^[ \t]*" bbdb-phone-main-regexp bbdb-phone-ext-regexp "$")) +(defconst bbdb-phone-regexp-4 (concat "^[ \t]*" bbdb-phone-main-regexp "$")) +(defconst bbdb-phone-regexp-5 (concat "^[ \t]*" bbdb-phone-ext-regexp "$")) + +(defun bbdb-parse-phone-number (string &optional number-type) + "Parse a phone number from STRING and return a list of integers the form +\(area-code exchange number) or (area-code exchange number extension). +This is both lenient and strict in what it will parse - whitespace may +appear (or not) between any of the groups of digits, parentheses around the +area code are optional, as is a dash between the exchange and number, and +a '1' preceeding the area code; but there must be three digits in the area +code and exchange, and four in the number (if they are present). An error +will be signalled if unparsable. All of these are unambigously parsable: + + ( 415 ) 555 - 1212 x123 -> (415 555 1212 123) + (415)555-1212 123 -> (415 555 1212 123) + (1-415) 555-1212 123 -> (415 555 1212 123) + 1 (415)-555-1212 123 -> (415 555 1212 123) + 555-1212 123 -> (0 555 1212 123) + 555 1212 -> (0 555 1212) + 415 555 1212 -> (415 555 1212) + 1 415 555 1212 -> (415 555 1212) + 5551212 -> (0 555 1212) + 4155551212 -> (415 555 1212) + 4155551212123 -> (415 555 1212 123) + 5551212x123 -> (0 555 1212 123) + 1234 -> (0 0 0 1234) + +Note that \"4151212123\" is ambiguous; it could be interpreted either as +\"(415) 121-2123\" or as \"415-1212 x123\". + +\(And uh, oh yeah, this does little if `bbdb-north-american-phone-numbers-p' +is nil...\)" + + (cond ((if number-type + (eq number-type 'euro) + (not bbdb-north-american-phone-numbers-p)) + (list (bbdb-string-trim string))) + ((string-match bbdb-phone-regexp-1 string) + ;; (415) 555-1212 x123 + (list (bbdb-subint string 1) (bbdb-subint string 2) + (bbdb-subint string 3) (bbdb-subint string 4))) + ((string-match bbdb-phone-regexp-2 string) + ;; (415) 555-1212 + (list (bbdb-subint string 1) (bbdb-subint string 2) + (bbdb-subint string 3))) + ((string-match bbdb-phone-regexp-3 string) + ;; 555-1212 x123 + (list 0 (bbdb-subint string 1) (bbdb-subint string 2) + (bbdb-subint string 3))) + ((string-match bbdb-phone-regexp-4 string) + ;; 555-1212 + (list 0 (bbdb-subint string 1) (bbdb-subint string 2))) + ((string-match bbdb-phone-regexp-5 string) + ;; x123 + (list 0 0 0 (bbdb-subint string 1))) + (t (error "phone number unparsable.")))) + +;;; Parsing other things + +(defcustom bbdb-expand-mail-aliases t + "If non-nil, expand mail aliases in `bbdb-complete-name'." + :group 'bbdb-record-use + :type 'boolean) + +(defcustom bbdb-check-zip-codes-p t + "If non-nil, require legal zip codes when entering an address. +The format of legal zip codes is determined by the variable +`bbdb-legal-zip-codes'." + :group 'bbdb-record-creation + :type 'boolean) + +(defcustom bbdb-legal-zip-codes + '(;; empty string + "^$" + ;; Matches 1 to 6 digits. + "^[ \t\n]*[0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[ \t\n]*$" + ;; Matches 5 digits and 3 or 4 digits. + "^[ \t\n]*\\([0-9][0-9][0-9][0-9][0-9]\\)[ \t\n]*-?[ \t\n]*\\([0-9][0-9][0-9][0-9]?\\)[ \t\n]*$" + ;; Match zip codes for Canada, UK, etc. (result is ("LL47" "U4B")). + "^[ \t\n]*\\([A-Za-z0-9]+\\)[ \t\n]+\\([A-Za-z0-9]+\\)[ \t\n]*$" + ;; Match zip codes for continental Europe. Examples "CH-8057" + ;; or "F - 83320" (result is ("CH" "8057") or ("F" "83320")). + ;; Support for "NL-2300RA" added at request from Carsten Dominik + ;; + "^[ \t\n]*\\([A-Z]+\\)[ \t\n]*-?[ \t\n]*\\([0-9]+ ?[A-Z]*\\)[ \t\n]*$" + ;; Match zip codes from Sweden where the five digits are grouped 3+2 + ;; at the request from Mats Lofdahl . + ;; (result is ("SE" (133 36))) + "^[ \t\n]*\\([A-Z]+\\)[ \t\n]*-?[ \t\n]*\\([0-9]+\\)[ \t\n]+\\([0-9]+\\)[ \t\n]*$") + "List of regexps that match legal zip codes. +Whether this is used at all depends on the variable `bbdb-check-zip-codes-p'." + :group 'bbdb-record-creation + :type '(repeat regexp)) + +(defun bbdb-parse-zip-string (string) + "Check whether STRING is a legal zip code. +Do this only if `bbdb-check-zip-codes-p' is non-nil." + (if (and bbdb-check-zip-codes-p + (not (memq t (mapcar (lambda (regexp) + ;; if it matches, (not (not index-of-match)) returns t + (not (not (string-match regexp string)))) + bbdb-legal-zip-codes)))) + (error "not a valid zip code.") + string)) + +(defun bbdb-read-new-record () + "Prompt for and return a completely new BBDB record. +Doesn't insert it in to the database or update the hashtables, but does +ensure that there will not be name collisions." + (bbdb-records) ; make sure database is loaded + (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.")) + (let (firstname lastname) + (bbdb-error-retry + (progn + (if current-prefix-arg + (setq firstname (bbdb-read-string "First Name: ") + lastname (bbdb-read-string "Last Name: ")) + (let ((names (bbdb-divide-name (bbdb-read-string "Name: ")))) + (setq firstname (car names) + lastname (nth 1 names)))) + (if (string= firstname "") (setq firstname nil)) + (if (string= lastname "") (setq lastname nil)) + (if (and bbdb-no-duplicates-p + (bbdb-gethash (bbdb-build-name firstname lastname))) + (error "%s %s is already in the database" + (or firstname "") (or lastname ""))))) + (let ((company (bbdb-read-string "Company: ")) + (net (bbdb-split (bbdb-read-string "Network Address: ") ",")) + (addrs + (let (L L-tail str addr) + (while (not (string= + "" + (setq str + (bbdb-read-string + "Address Description [RET when no more]: " + "" + (mapcar (function (lambda(x) (list x))) + (bbdb-label-completion-list + "addresses")))))) + (setq addr (make-vector bbdb-address-length nil)) + (bbdb-record-edit-address addr str) + (if L + (progn (setcdr L-tail (cons addr nil)) + (setq L-tail (cdr L-tail))) + (setq L (cons addr nil) + L-tail L))) + L)) + (phones + (let (L L-tail str) + (while (not (string= + "" + (setq str + (bbdb-read-string + "Phone Location [RET when no more]: " + "" + (mapcar (function (lambda(x) (list x))) + (bbdb-label-completion-list + "phones")))))) + (let* ((phonelist + (bbdb-error-retry + (bbdb-parse-phone-number + (read-string "Phone: " + (and (integerp bbdb-default-area-code) + (format "(%03d) " + bbdb-default-area-code)))))) + (phone (apply 'vector str + (if (= 3 (length phonelist)) + (nconc phonelist '(0)) + phonelist)))) + (if L + (progn (setcdr L-tail (cons phone nil)) + (setq L-tail (cdr L-tail))) + (setq L (cons phone nil) + L-tail L)))) + L)) + (notes (bbdb-read-string "Additional Comments: "))) + (if (string= company "") (setq company nil)) + (if (string= notes "") (setq notes nil)) + (let ((record + (vector firstname lastname nil company phones addrs net notes + (make-vector bbdb-cache-length nil)))) + record)))) + +;;;###autoload +(defun bbdb-create (record) + "Add a new entry to the bbdb database ; prompts for all relevant info +using the echo area, inserts the new record in the db, sorted alphabetically, +and offers to save the db file. DO NOT call this from a program. Call +bbdb-create-internal instead." + (interactive (list (bbdb-read-new-record))) + (bbdb-invoke-hook 'bbdb-create-hook record) + (bbdb-change-record record t) + (bbdb-display-records (list record))) + + +(defmacro bbdb-check-type (place predicate) + (list 'while (list 'not (list predicate place)) + (nconc (cond ((eq (car-safe place) 'aref) + (list 'aset (nth 1 place) (nth 2 place))) + ((eq (car-safe place) 'car) + (list 'setcar (nth 1 place))) + ((eq (car-safe place) 'cdr) + (list 'setcdr (nth 1 place))) + (t (list 'setq place))) + (list + (list 'signal ''wrong-type-argument + (list 'list (list 'quote predicate) place)))))) + +(defun bbdb-create-internal (name company net addrs phones notes) + "Adds a record to the database; this function does a fair amount of +error-checking on the passed in values, so it's safe to call this from +other programs. + +NAME is a string, the name of the person to add. An error is signalled +if that name is already in use and `bbdb-no-duplicates-p' is t. +COMPANY is a string or nil. +NET is a comma-separated list of email addresses, or a list of strings. +An error is signalled if that name is already in use. +ADDRS is a list of address objects. An address is a vector of the form + [\"location\" (\"line1\" \"line2\" ... ) \"City\" \"State\" \"Zip\" \"Country\"]. +PHONES is a list of phone-number objects. A phone-number is a vector of +the form + [\"location\" areacode prefix suffix extension-or-nil] +or + [\"location\" \"phone-number\"] +NOTES is a string, or an alist associating symbols with strings." + (let (firstname lastname aka) + (while (and (progn + (setq name (and name (bbdb-divide-name name)) + firstname (car name) + lastname (nth 1 name)) + (bbdb-gethash (bbdb-build-name firstname lastname))) + bbdb-no-duplicates-p) + (setq name (signal 'error + (list (format "%s %s is already in the database" + (or firstname "") (or lastname "")))))) + (and company (bbdb-check-type company stringp)) + (if (stringp net) + (setq net (bbdb-split net ","))) + (if bbdb-no-duplicates-p + (let ((rest net)) + (while rest + (while (bbdb-gethash (downcase (car rest))) + (setcar rest + (signal 'error (list (format + "%s is already in the database" + (car rest)))))) + (setq rest (cdr rest))))) + (setq addrs + (mapcar + (lambda (addr) + (while (or (not (vectorp addr)) + (/= (length addr) bbdb-address-length)) + (setq addr (signal 'wrong-type-argument (list 'vectorp addr)))) + (bbdb-check-type (aref addr 0) stringp) ;;; XXX use bbdb-addresses + (bbdb-check-type (aref addr 1) listp) + (bbdb-check-type (aref addr 2) stringp) + (bbdb-check-type (aref addr 3) stringp) + (bbdb-check-type (aref addr 4) stringp) + (bbdb-check-type (aref addr 5) stringp) + addr) + addrs)) + (setq phones + (mapcar + (lambda (phone) + (while (or (not (vectorp phone)) + (and (/= (length phone) 2) + (/= (length phone) bbdb-phone-length))) + (setq phone + (signal 'wrong-type-argument (list 'vectorp phone)))) + (bbdb-check-type (aref phone 0) stringp) + (if (= 2 (length phone)) + (bbdb-check-type (aref phone 1) stringp) + (bbdb-check-type (aref phone 1) integerp) + (bbdb-check-type (aref phone 2) integerp) + (bbdb-check-type (aref phone 3) integerp) + (and (aref phone 4) (bbdb-check-type (aref phone 4) integerp)) + (if (eq 0 (aref phone 4)) (aset phone 4 nil))) + phone) + phones)) + (or (stringp notes) + (setq notes + (mapcar (lambda (note) + (bbdb-check-type note consp) + (bbdb-check-type (car note) symbolp) + (if (consp (cdr note)) + (setq note (cons (car note) (car (cdr note))))) + (bbdb-check-type (cdr note) stringp) + note) + notes))) + (let ((record + (vector firstname lastname aka company phones addrs net notes + (make-vector bbdb-cache-length nil)))) + (bbdb-invoke-hook 'bbdb-create-hook record) + (bbdb-change-record record t) + record))) + + +;;; bbdb-mode stuff + +(defun bbdb-current-record (&optional planning-on-modifying) + "Returns the record which the point is point at. In linear time, man..." + (if (and planning-on-modifying bbdb-readonly-p) + (error "The Insidious Big Brother Database is read-only.")) + (if (not (equal bbdb-buffer-name (buffer-name (current-buffer)))) + (error "this command only works while in the \"%s\" buffer." + bbdb-buffer-name)) + (let ((p (point)) + (rest bbdb-records) + (rec nil)) + (while (and (cdr rest) (not rec)) + (if (> (nth 2 (car (cdr rest))) p) + (setq rec (car (car rest)))) + (setq rest (cdr rest))) + (or rec (car (car rest))))) + + +;; yow, are we object oriented yet? +(defun bbdb-record-get-field-internal (record field) + (cond ((eq field 'name) (bbdb-record-name record)) + ((eq field 'net) (bbdb-record-net record)) + ((eq field 'aka) (bbdb-record-aka record)) + ((eq field 'phone) (bbdb-record-phones record)) + ((eq field 'address) (bbdb-record-addresses record)) + ((eq field 'property) (bbdb-record-raw-notes record)) + (t (error "doubleplus ungood: unknown field type %s" field)))) + +(defun bbdb-record-store-field-internal (record field value) + (cond ((eq field 'name) (error "doesn't work on names")) + ((eq field 'net) (bbdb-record-set-net record value)) + ((eq field 'aka) (bbdb-record-set-aka record value)) + ((eq field 'phone) (bbdb-record-set-phones record value)) + ((eq field 'address) (bbdb-record-set-addresses record value)) + ((eq field 'property) (bbdb-record-set-raw-notes record value)) + (t (error "doubleplus ungood: unknown field type %s" field)))) + +(defun bbdb-record-edit-field-internal (record field &optional which location) + (cond ((eq field 'name) (bbdb-record-edit-name record)) + ((eq field 'company) (bbdb-record-edit-company record)) + ((eq field 'net) (bbdb-record-edit-net record)) + ((eq field 'aka) (bbdb-record-edit-aka record)) + ((eq field 'phone) (bbdb-record-edit-phone which location)) + ((eq field 'address) (bbdb-record-edit-address which location)) + ((eq field 'property) (bbdb-record-edit-property record (car which))) + (t (error "doubleplus ungood: unknown field type %s" field)))) + + +(defun bbdb-current-field (&optional planning-on-modifying) + (or (bbdb-current-record planning-on-modifying) + (error "unperson")) + (delete 'field-name (get-text-property (point) 'bbdb-field))) + +;;;###autoload +(defun bbdb-apply-next-command-to-all-records () + "Typing \\\\[bbdb-apply-next-command-to-all-records] \ +in the *BBDB* buffer makes the next command operate on all +of the records currently displayed. \(Note that this only works for +certain commands.\)" + (interactive) + (message (substitute-command-keys + "\\\\[bbdb-apply-next-command-to-all-records] - ")) + (setq prefix-arg current-prefix-arg + last-command this-command) + nil) + +(defmacro bbdb-do-all-records-p () + "Whether the last command was `bbdb-apply-next-command-to-all-records'." + '(eq last-command 'bbdb-apply-next-command-to-all-records)) + + +(defvar bbdb-append-records nil) + +;;;###autoload +(defun bbdb-append-records-p () + (cond ((eq t bbdb-append-records)) + ((numberp bbdb-append-records) + (setq bbdb-append-records + (1- bbdb-append-records)) + (when (= 0 bbdb-append-records) + (when (not bbdb-silent-running) + (message "No further search results will be appended.") + (sit-for 2)) + (setq bbdb-append-records nil)) + t) + (bbdb-append-records + (setq bbdb-append-records nil) + t) + (t nil))) + +;;;###autoload +(defun bbdb-append-records (arg) + "Typing \\\\[bbdb-append-records] \ +in the *BBDB* buffer makes the next search/display command to append +new records to those in the *BBDB* buffer. + +With an prefix arg (C-u) toggle between always append and no append. +With an prefix arg that is a positive number append will be enabled for that +many times. +With any other argument append will be enabled once." + (interactive "P") + (message (substitute-command-keys + "\\\\[bbdb-append-records] - ")) + (setq bbdb-append-records + (cond ((and arg (listp arg)) + (if (not bbdb-silent-running) + (if (not bbdb-append-records) + (message "Always append records.") + (message "Do not append records."))) + (not bbdb-append-records)) + ((and (numberp arg) (< 1 arg)) + (if (not bbdb-silent-running) + (message "Append records for the next %d times." arg)) + arg) + (t 'once)))) + +;;;###autoload +(defun bbdb-insert-new-field (record name contents) + "Add a new field to the current record; the field type and contents +are prompted for if not supplied. + +If you are inserting a new phone-number field, you can control whether +it is a north american or european phone number by providing a prefix +argument. A prefix arg of ^U means it's to be a euronumber, and any +other prefix arg means it's to be a a structured north american number. +Otherwise, which style is used is controlled by the variable +`bbdb-north-american-phone-numbers-p'. + +If you are inserting a new net address, you can have BBDB append a +default domain to any net address that does not contain one. Set +`bbdb-default-domain' to a string such as \"mycompany.com\" (or, +depending on your environment, (getenv \"DOMAINNAME\")), and +\"@mycompany.com\" will be appended to an address that is entered as +just a username. A prefix arg of ^U (or a `bbdb-default-domain' +value of \"\", the default) means do not alter the address." + (interactive (let ((record (or (bbdb-current-record t) + (error "current record unexists!"))) + (name "") + (completion-ignore-case t)) + (while (string= name "") + (setq name + (downcase + (completing-read "Insert Field: " + (append '(("phone") ("address") + ("net") ("AKA") ("notes")) + (bbdb-propnames)) + nil + nil ; used to be t + nil)))) + (setq name (intern name)) + (list record name (bbdb-prompt-for-new-field-value name)))) + (if (null contents) + (setq contents (bbdb-prompt-for-new-field-value name))) + + (cond ((eq name 'phone) + (bbdb-record-set-phones record + (nconc (bbdb-record-phones record) + (list contents)))) + ((eq name 'address) + (bbdb-record-set-addresses record + (nconc (bbdb-record-addresses record) + (list contents)))) + ((eq name 'net) + (if (bbdb-record-net record) + (error "There already are net addresses!")) + (if (stringp contents) + (setq contents (bbdb-split contents ","))) + ;; first detect any conflicts.... + (if bbdb-no-duplicates-p + (let ((nets contents)) + (while nets + (let ((old (bbdb-gethash (downcase (car nets))))) + (if (and old (not (eq old record))) + (error "net address \"%s\" is used by \"%s\"" + (car nets) + (or (bbdb-record-name old) + (car (bbdb-record-net old)))))) + (setq nets (cdr nets))))) + ;; then store. + (let ((nets contents)) + (while nets + (bbdb-puthash (downcase (car nets)) record) + (setq nets (cdr nets)))) + (bbdb-record-set-net record contents)) + ((eq name 'aka) + (if (bbdb-record-aka record) + (error "there already are alternate names!")) + (if (stringp contents) + (setq contents (bbdb-split contents ";"))) + ;; first detect any conflicts.... + (if bbdb-no-duplicates-p + (let ((aka contents)) + (while aka + (let ((old (bbdb-gethash (downcase (car aka))))) + (if (and old (not (eq old record))) + (error "alternate name \"%s\" is used by \"%s\"" + (car aka) + (or (bbdb-record-name old) + (car (bbdb-record-net old)))))) + (setq aka (cdr aka))))) + ;; then store. + (let ((aka contents)) + (while aka + (bbdb-puthash (downcase (car aka)) record) + (setq aka (cdr aka)))) + (bbdb-record-set-aka record contents)) + ((eq name 'notes) + (if (bbdb-record-notes record) (error "there already are notes!")) + (bbdb-record-set-notes record contents)) + ((assoc (symbol-name name) (bbdb-propnames)) + (if (and (consp (bbdb-record-raw-notes record)) + (assq name (bbdb-record-raw-notes record))) + (error "there is already a \"%s\" note!" name)) + (bbdb-record-putprop record name contents)) + (t (error "doubleplus ungood: unknow how to set slot %s" name))) + (bbdb-change-record record nil) +; (bbdb-offer-save) + (let ((bbdb-display-layout nil)) + (bbdb-redisplay-one-record record))) + +(defun bbdb-prompt-for-new-field-value (name) + (cond ((eq name 'net) + (let + ((n (bbdb-read-string "Net: "))) + (if (string-match "^mailto:" n) + (setq n (substring n (match-end 0)))) + (if (or (eq nil bbdb-default-domain) + current-prefix-arg (string-match "[@%!]" n)) + n + (concat n "@" bbdb-default-domain)))) + ((eq name 'aka) (bbdb-read-string "Alternate Names: ")) + ((eq name 'phone) + (let ((p (make-vector + (if (if current-prefix-arg + (numberp current-prefix-arg) + bbdb-north-american-phone-numbers-p) + bbdb-phone-length + 2) + 0))) + (aset p 0 nil) + (aset p 1 + (if (= bbdb-phone-length (length p)) + (if (integerp bbdb-default-area-code) + bbdb-default-area-code + 0) + nil)) + (bbdb-record-edit-phone p) + p)) + ((eq name 'address) + (let ((a (make-vector bbdb-address-length nil))) + (bbdb-record-edit-address a) + a)) + ((eq name 'notes) (bbdb-read-string "Notes: ")) + ((assoc (symbol-name name) (bbdb-propnames)) + (bbdb-read-string (format "%s: " name))) + (t + (if (bbdb-y-or-n-p + (format "\"%s\" is an unknown field name. Define it? " name)) + (bbdb-set-propnames + (append (bbdb-propnames) (list (list (symbol-name name))))) + (error "unknown field \"%s\"" name)) + (bbdb-read-string (format "%s: " name))))) + +(defun bbdb-add-new-field (name) + "Programmatically add a new field called NAME. Returns the list of propnames." + ;; check that we don't have one already; if we do, return quietly. + (if (assoc (symbol-name name) (append '(("phone") ("address") ("net") + ("AKA") ("notes")) + (bbdb-propnames))) + bbdb-propnames + (bbdb-set-propnames (append (bbdb-propnames) + (list (list (symbol-name name))))))) + +;;;###autoload +(defun bbdb-edit-current-field () + "Edit the contents of the Insidious Big Brother Database field displayed on +the current line (this is only meaningful in the \"*BBDB*\" buffer.) If the +cursor is in the middle of a multi-line field, such as an address or comments +section, then the entire field is edited, not just the current line." + (interactive) + ;; when at the end of the line take care of it + (if (and (eolp) (not (bobp)) (not (bbdb-current-field t))) + (backward-char 1)) + + (let* ((record (bbdb-current-record t)) + (field (bbdb-current-field t)) + need-to-sort) + (or field (error "on an unfield")) + (setq need-to-sort + (apply 'bbdb-record-edit-field-internal record field)) + (bbdb-change-record record need-to-sort) + (bbdb-redisplay-one-record record) + ;; (bbdb-offer-save) + (if (and (eq 'property (car field)) + (or (eq 'mail-alias (caadr field)) + (eq 'net (caadr field)))) + (setq bbdb-define-all-aliases-needs-rebuilt 'edit)) + )) + +(defun bbdb-record-edit-name (bbdb-record) + (let (fn ln co need-to-sort new-name old-name) + (bbdb-error-retry + (progn + (if current-prefix-arg + (setq fn (bbdb-read-string "First Name: " + (bbdb-record-firstname bbdb-record)) + ln (bbdb-read-string "Last Name: " + (bbdb-record-lastname bbdb-record))) + (let ((names (bbdb-divide-name + (bbdb-read-string "Name: " + (bbdb-record-name bbdb-record))))) + (setq fn (car names) + ln (nth 1 names)))) + (setq need-to-sort + (or (not (string= fn + (or (bbdb-record-firstname bbdb-record) ""))) + (not (string= ln + (or (bbdb-record-lastname bbdb-record) ""))))) + (if (string= "" fn) (setq fn nil)) + (if (string= "" ln) (setq ln nil)) + ;; check for collisions + (setq new-name (if (and fn ln) (concat fn " " ln) + (or fn ln)) + old-name (bbdb-record-name bbdb-record)) + (if (and bbdb-no-duplicates-p + new-name + (not (and old-name (string= (downcase new-name) + (downcase old-name)))) + (bbdb-gethash (downcase new-name))) + (error "%s is already in the database!" new-name)))) + (setq co (bbdb-read-string "Company: " + (bbdb-record-company bbdb-record))) + (if (string= "" co) (setq co nil)) + (setq need-to-sort + (or need-to-sort + (not (equal (if co (downcase co) "") + (downcase (or (bbdb-record-company bbdb-record) + "")))))) + ;; + ;; delete the old hash entry + (let ((name (bbdb-record-name bbdb-record)) + (company (bbdb-record-company bbdb-record))) + (if (> (length name) 0) + (bbdb-remhash (downcase name) bbdb-record)) + (if (> (length company) 0) + (bbdb-remhash (downcase company) bbdb-record))) + (bbdb-record-set-namecache bbdb-record nil) + (bbdb-record-set-firstname bbdb-record fn) + (bbdb-record-set-lastname bbdb-record ln) + (bbdb-record-set-company bbdb-record co) + ;; add a new hash entry + (and (or fn ln) + (bbdb-puthash (downcase (bbdb-record-name bbdb-record)) + bbdb-record)) + need-to-sort)) + +(defun bbdb-record-edit-company (bbdb-record) + (let ((co (bbdb-read-string "Company: " (bbdb-record-company bbdb-record))) + need-to-sort) + + (if (string= "" co) (setq co nil)) + (setq need-to-sort + (or need-to-sort + (not (equal (if co (downcase co) "") + (downcase (or (bbdb-record-company bbdb-record) + "")))))) + + ;; delete the old hash entry + (let ((name (bbdb-record-name bbdb-record)) + (company (bbdb-record-company bbdb-record))) + (if (> (length name) 0) + (bbdb-remhash (downcase name) bbdb-record)) + (if (> (length company) 0) + (bbdb-remhash (downcase company) bbdb-record))) + + (bbdb-record-set-company bbdb-record co) + ;; add a new hash entry + (bbdb-puthash (downcase (bbdb-record-name bbdb-record)) + bbdb-record) + + need-to-sort)) + +(defun bbdb-address-edit-default (addr) + "Function to use for address editing. +The sub-fields are queried using the default order and using the +default names. Set `bbdb-address-editing-function' to an alternate +address editing function if you don't like this function. It is +mostly used for US style addresses. + +The sub-fields and the prompts used are: +Street, line n: (nth n street) +City: city +State: state +Zip Code: zip +Country: country" + (let* ((str (let ((l) (s) (n 0)) + (while (not (string= "" (setq s (bbdb-read-string + (format "Street, line %d: " (+ 1 n)) + (nth n (bbdb-address-streets addr)))))) + (setq l (append l (list s))) + (setq n (1+ n))) + l)) + (cty (bbdb-read-string "City: " (bbdb-address-city addr))) + (ste (bbdb-read-string "State: " (bbdb-address-state addr))) + (zip (bbdb-error-retry + (bbdb-parse-zip-string + (bbdb-read-string "Zip Code: " (bbdb-address-zip-string addr))))) + (country (bbdb-read-string "Country: " (or (bbdb-address-country addr) + bbdb-default-country)))) + (bbdb-address-set-streets addr str) + (bbdb-address-set-city addr cty) + (bbdb-address-set-state addr ste) + (bbdb-address-set-zip addr zip) + (if (string= "" (concat cty ste zip country (mapconcat 'identity str ""))) + ;; user didn't enter anything. this causes a display bug. this + ;; is a temporary fix. Ideally, we'd simply discard the entire + ;; address entry, but that's going to require bigger hacking. + (bbdb-address-set-country addr "Emacs") + (bbdb-address-set-country addr country)) + nil)) + +(defun bbdb-address-edit-continental (addr) + "Function to use for address editing. +The sub-fields are queried using the default order and using the +default names. Set `bbdb-address-editing-function' to an alternate +address editing function if you don't like this function. It is +mostly used for US style addresses. + +The sub-fields and the prompts used are: +Street, line n: (nth n street) +City: city +State: state +Zip Code: zip +Country: country" + (let* ((str (let ((l) (s) (n 0)) + (while (not (string= "" (setq s (bbdb-read-string + (format "Street, line %d: " (+ 1 n)) + (nth n (bbdb-address-streets addr)))))) + (setq l (append l (list s))) + (setq n (1+ n))) + l)) + (zip (bbdb-error-retry + (bbdb-parse-zip-string + (bbdb-read-string "Zip Code: " (bbdb-address-zip-string addr))))) + (cty (bbdb-read-string "City: " (bbdb-address-city addr))) + (ste "") + (country (bbdb-read-string "Country: " (or (bbdb-address-country addr) + bbdb-default-country)))) + (bbdb-address-set-streets addr str) + (bbdb-address-set-city addr cty) + (bbdb-address-set-state addr ste) + (bbdb-address-set-zip addr zip) + (if (string= "" (concat cty ste zip country (mapconcat 'identity str ""))) + ;; user didn't enter anything. this causes a display bug. this + ;; is a temporary fix. Ideally, we'd simply discard the entire + ;; address entry, but that's going to require bigger hacking. + (bbdb-address-set-country addr "Emacs") + (bbdb-address-set-country addr country)) + nil)) + +(defcustom bbdb-address-editing-function 'bbdb-address-edit-default + "Function to use for address editing. +The function must accept a BBDB address as parameter and allow the +user to edit it. This variable is called from `bbdb-record-edit-address'. +The default value is the symbol `bbdb-address-edit-default'." + :group 'bbdb-record-creation + :type 'function) + +(defun bbdb-record-edit-address (addr &optional location) + "Edit an address ADDR. +If optional parameter LOCATION is nil, edit the location sub-field +of the address as well. The address itself is edited using the editing +function in `bbdb-address-editing-function'." + (let ((loc + (or location (bbdb-read-string "Location: " + (or (bbdb-address-location addr) + (bbdb-label-completion-default + "addresses")) + (mapcar (function (lambda(x) (list x))) + (bbdb-label-completion-list + "addresses")))))) + (bbdb-address-set-location addr loc)) + (if current-prefix-arg + (bbdb-address-edit-default addr) + (funcall bbdb-address-editing-function addr))) + +(defun bbdb-record-edit-phone (phone-number &optional location) + (let ((newl (or location + (bbdb-read-string "Location: " + (or (bbdb-phone-location phone-number) + (bbdb-label-completion-default + "phones")) + (mapcar (function (lambda(x) (list x))) + (bbdb-label-completion-list + "phones"))))) + (newp (let ((bbdb-north-american-phone-numbers-p + (= (length phone-number) bbdb-phone-length))) + (bbdb-error-retry + (bbdb-parse-phone-number + (read-string "Phone: " (bbdb-phone-string phone-number))))))) + (bbdb-phone-set-location phone-number newl) + (bbdb-phone-set-area phone-number (nth 0 newp)) ; euronumbers too. + (if (= (length phone-number) 2) + nil + (bbdb-phone-set-exchange phone-number (nth 1 newp)) + (bbdb-phone-set-suffix phone-number (nth 2 newp)) + (bbdb-phone-set-extension phone-number (or (nth 3 newp) 0)))) + nil) + +(defun bbdb-record-edit-net (bbdb-record) + (let ((str (bbdb-read-string "Net: " + (mapconcat (function identity) + (bbdb-record-net bbdb-record) + ", ")))) + (let ((oldnets (bbdb-record-net bbdb-record)) + (newnets (bbdb-split str ","))) + ;; first check for any conflicts... + (if bbdb-no-duplicates-p + (let ((rest newnets)) + (while rest + (let ((old (delete bbdb-record (bbdb-gethash (downcase (car rest)))))) + (if old + (error "net address \"%s\" is used by \"%s\"" + (car rest) (mapconcat (lambda (r) (bbdb-record-name r)) + old ", ")))) + (setq rest (cdr rest))))) + ;; then update. + (let ((rest oldnets)) + (while rest + (bbdb-remhash (downcase (car rest)) bbdb-record) + (setq rest (cdr rest)))) + (let ((nets newnets)) + (while nets + (bbdb-puthash (downcase (car nets)) bbdb-record) + (setq nets (cdr nets)))) + (bbdb-record-set-net bbdb-record newnets))) + nil) + +(defun bbdb-record-edit-aka (bbdb-record) + (let ((str (bbdb-read-string "AKA: " + (mapconcat (function identity) + (bbdb-record-aka bbdb-record) + "; ")))) + (let ((oldaka (bbdb-record-aka bbdb-record)) + (newaka (bbdb-split str ";"))) + ;; first check for any conflicts... + (if bbdb-no-duplicates-p + (let ((rest newaka)) + (while rest + (let ((old (bbdb-gethash (downcase (car rest))))) + (if (and old (not (eq old bbdb-record))) + (error "alternate name address \"%s\" is used by \"%s\"" + (car rest) (bbdb-record-name old)))) + (setq rest (cdr rest))))) + ;; then update. + (let ((rest oldaka)) + (while rest + (bbdb-remhash (downcase (car rest)) bbdb-record) + (setq rest (cdr rest)))) + (let ((aka newaka)) + (while aka + (bbdb-puthash (downcase (car aka)) bbdb-record) + (setq aka (cdr aka)))) + (bbdb-record-set-aka bbdb-record newaka))) + nil) + +;;;###autoload +(defun bbdb-record-edit-notes (bbdb-record &optional regrind) + (interactive (list (bbdb-current-record t) t)) + (let ((notes (bbdb-read-string "Notes: " (bbdb-record-notes bbdb-record)))) + (bbdb-record-set-notes bbdb-record (if (string= "" notes) nil notes))) + (if regrind + (save-excursion + (set-buffer bbdb-buffer-name) + (bbdb-redisplay-one-record bbdb-record))) + nil) + +;;;###autoload +(defun bbdb-record-edit-property (bbdb-record &optional prop regrind) + (interactive (list (bbdb-current-record t) nil t)) + (let* ((propnames (bbdb-propnames)) + (propname (if prop (symbol-name prop) + (completing-read + (format "Edit property of %s: " + (bbdb-record-name bbdb-record)) + (cons '("notes") propnames)))) + (propsym (or prop (if (equal "" propname) 'notes (intern propname)))) + (string (bbdb-read-string (format "%s: " propname) + (bbdb-record-getprop bbdb-record propsym)))) + (bbdb-record-putprop bbdb-record propsym + (if (string= "" string) nil string))) + (if regrind + (save-excursion + (set-buffer bbdb-buffer-name) + (bbdb-redisplay-one-record bbdb-record))) + nil) + + +(defsubst bbdb-field-equal (x y) + (if (and (consp x) (consp y)) + (and (eq (car x) (car y)) + (eq (car (cdr x)) (car (cdr y))) + (eq (car (cdr (cdr x))) (car (cdr (cdr y))))) + (eq x y))) + +(defun bbdb-next-field (&optional count planning-on-modifying) + (or count (setq count 1)) + (beginning-of-line) + (let* ((record (bbdb-current-record planning-on-modifying)) + (field (bbdb-current-field planning-on-modifying)) + (next-record record) + (next-field field) + (signum (if (< count 0) -1 1)) + (i 0)) + (if (< count 0) (setq count (- count))) + (if field + (while (and next-field (< i count)) + (while (bbdb-field-equal next-field field) + (forward-line signum) + (setq next-record (bbdb-current-record planning-on-modifying) + next-field (bbdb-current-field planning-on-modifying)) + (or (eq next-record record) + (setq next-field nil))) + (setq i (1+ i)) + (setq field next-field))) + next-field)) + +;;;###autoload +(defun bbdb-transpose-fields (&optional arg) + "This is like the `transpose-lines' command, but it is for BBDB fields. +If the cursor is on a field of a BBDB record, that field and the previous +field will be transposed. + +With argument ARG, takes previous line and moves it past ARG fields. +With argument 0, interchanges field point is in with field mark is in. + +Both fields must be in the same record, and must be of the same basic type +\(that is, you can use this command to change the order in which phone-number +fields are listed, but you can't use it to make an address appear before a +phone number; the order of field types is fixed.\)" + (interactive "p") + (let ((record (bbdb-current-record t)) + moving-field position-after position-before + swap-p type list) + (if (/= arg 0) + (setq moving-field (or (bbdb-next-field -1 t) + (error "no previous field")) + position-after (bbdb-next-field arg t) + position-before (bbdb-next-field (if (< arg 0) -1 1) t)) + ;; if arg is 0, swap fields at point and mark + (setq swap-p t) + (setq position-after (bbdb-current-field)) + (save-excursion + (goto-char (mark)) + (setq moving-field (bbdb-current-field)) + (or (eq record (bbdb-current-record)) (error "not in the same record")))) + (if (< arg 0) + (let ((x position-after)) + (setq position-after position-before + position-before x) + (forward-line 2))) + (setq type (car moving-field)) + (or position-after position-before + (error "that would be out of the record!")) + (or (eq type (car position-after)) + (eq type (car position-before)) + (error "can't transpose fields of different types (%s and %s)" + type (if (eq type (car position-after)) + (car position-before) (car position-after)))) + (or (eq type (car position-after)) (setq position-after nil)) + (or (eq type (car position-before)) (setq position-before nil)) + (setq moving-field (nth 1 moving-field) + position-after (nth 1 position-after) + position-before (nth 1 position-before)) + (cond ((memq type '(name aka net)) + (error "there is only one %s field, so you can't transpose it" + type)) + ((memq type '(phone address property)) + (setq list (bbdb-record-get-field-internal record type))) + (t (error "doubleplus ungood: unknown field %s" type))) + (if swap-p + (let ((rest list)) + (while rest + (cond ((eq (car rest) moving-field) (setcar rest position-after)) + ((eq (car rest) position-after) (setcar rest moving-field))) + (setq rest (cdr rest)))) + (if (eq position-before (car list)) + (setq list (cons moving-field (delq moving-field list))) + (let ((rest list)) + (while (and rest (not (eq position-after (car rest)))) + (setq rest (cdr rest))) + (or rest (error "doubleplus ungood: couldn't reorder list")) + (let ((inhibit-quit t)) + (setq list (delq moving-field list)) + (setcdr rest (cons moving-field (cdr rest))))))) + (bbdb-record-store-field-internal record type list) + (bbdb-change-record record nil) + (bbdb-redisplay-one-record record))) + + +;;;###autoload +(defun bbdb-delete-current-field-or-record (&optional records noprompt) + "Delete the line which the cursor is on; actually, delete the field which +that line represents from the database. If the cursor is on the first line +of a database entry (the name/company line) then the entire entry will be +deleted." + (interactive (list (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (list (bbdb-current-record))) + current-prefix-arg)) + (let* ((field (bbdb-current-field t)) + (type (car field)) + record + (name (cond ((null field) (error "on an unfield")) + ((eq type 'property) (symbol-name (car (nth 1 field)))) + (t (symbol-name type))))) + (while records + (setq record (car records)) + (if (eq type 'name) + (bbdb-delete-current-record record noprompt) + (if (not (or noprompt + (bbdb-y-or-n-p (format "delete this %s field (of %s)? " + name + (bbdb-record-name record))))) + nil + (cond ((memq type '(phone address)) + (bbdb-record-store-field-internal + record type + (delq (nth 1 field) + (bbdb-record-get-field-internal record type)))) + ((memq type '(net aka)) + (let ((rest (bbdb-record-get-field-internal record type))) + (while rest + (bbdb-remhash (downcase (car rest)) record) + (setq rest (cdr rest)))) + (bbdb-record-store-field-internal record type nil)) + ((eq type 'property) + (bbdb-record-putprop record (car (nth 1 field)) nil)) + (t (error "doubleplus ungood: unknown field type"))) + (bbdb-change-record record nil) + (bbdb-redisplay-one-record record))) + (setq records (cdr records))))) + +;;;###autoload +(defun bbdb-delete-current-record (recs &optional noprompt) + "Delete the entire bbdb database entry which the cursor is within. +Pressing \\\\[bbdb-apply-next-command-to-all-records] will +delete all records listed in the BBDB buffer." + (interactive (list (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (list (bbdb-current-record t))) + current-prefix-arg)) + (if (not (listp recs)) + (setq recs (list recs))) + (while recs + (let ((r (car recs))) + (setq recs (cdr recs)) + (bbdb-debug (if (bbdb-record-deleted-p r) + (error "deleting deleted record"))) + (if (or noprompt + (bbdb-y-or-n-p (format "delete the entire db entry of %s? " + (or (bbdb-record-name r) + (bbdb-record-company r) + (car (bbdb-record-net r)))))) + (let* ((record-cons (assq r bbdb-records)) + (next-record-cons (car (cdr (memq record-cons + bbdb-records))))) + (bbdb-debug (if (bbdb-record-deleted-p r) + (error "deleting deleted record"))) + (bbdb-record-set-deleted-p r t) + (bbdb-delete-record-internal r) + (if (eq record-cons (car bbdb-records)) + (setq bbdb-records (cdr bbdb-records)) + (let ((rest bbdb-records)) + (while (cdr rest) + (if (eq record-cons (car (cdr rest))) + (progn + (setcdr rest (cdr (cdr rest))) + (setq rest nil))) + (setq rest (cdr rest))))) + (bbdb-redisplay-one-record r record-cons next-record-cons t) + (bbdb-with-db-buffer + (setq bbdb-changed-records (delq r bbdb-changed-records))) + ;; (bbdb-offer-save) + ))))) + +(defun bbdb-change-records-state-and-redisplay (desired-state records) + (let (rec) + (while records + (setq rec (car records)) + (unless (eq desired-state (nth 1 rec)) + (setcar (cdr rec) desired-state) + (bbdb-redisplay-one-record (car rec) rec)) + (setq records (cdr records))))) + +;;;###autoload +(defun bbdb-toggle-all-records-display-layout (arg &optional records) + "Show all the fields of all visible records. +Like `bbdb-toggle-records-display-layout' but for all visible records." + (interactive "P") + (if (null records) + (setq records bbdb-records)) + (let* ((record (bbdb-current-record)) + (cons (assq record bbdb-records)) + (current-state (nth 1 cons)) + (layout-alist + (or (delete nil (mapcar (lambda (l) + (if (and (assoc 'toggle l) + (cdr (assoc 'toggle l))) + l)) + bbdb-display-layout-alist)) + bbdb-display-layout-alist)) + (desired-state (assoc current-state layout-alist))) + (setq desired-state + (cond ((eq arg 0) + 'one-line) + ((null current-state) + 'multi-line) + ((null (cdr (memq desired-state layout-alist))) + (caar layout-alist)) + (t + (caadr (memq desired-state layout-alist))))) + (message "Using %S layout" desired-state) + (bbdb-change-records-state-and-redisplay desired-state records))) + +;;;###autoload +(defun bbdb-toggle-records-display-layout (arg) + "Toggle whether the current record is displayed expanded or elided +\(multi-line or one-line display.\) With a numeric argument of 0, the +current record will unconditionally be made elided; with any other argument, +the current record will unconditionally be shown expanded. +\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-toggle-records-display-layout]\" is \ +used instead of simply \"\\[bbdb-toggle-records-display-layout]\", then the state of all \ +records will +be changed instead of just the one at point. In this case, an argument +of 0 means that all records will unconditionally be made elided; any other +numeric argument means that all of the records will unconditionally be shown +expanded; and no numeric argument means that the records are made to be in +the opposite state of the record under point." + (interactive "P") + (bbdb-toggle-all-records-display-layout + arg + (if (not (bbdb-do-all-records-p)) + (list (assq (bbdb-current-record) bbdb-records))))) + +;;;###autoload +(defun bbdb-display-all-records-completely + (arg &optional records) + "Show all the fields of all currently displayed records. +The display layout `full-multi-line' is used for this." + (interactive "P") + (if (null records) + (setq records bbdb-records)) + (let* ((record (bbdb-current-record)) + (cons (assq record bbdb-records)) + (current-state (nth 1 cons)) + (desired-state + (cond ((not (eq current-state 'full-multi-line)) + 'full-multi-line) + (t + 'multi-line)))) + (bbdb-change-records-state-and-redisplay desired-state records))) + +;;;###autoload +(defun bbdb-display-record-completely (arg) + "Show all the fields of the current record. +The display layout `full-multi-line' is used for this." + (interactive "P") + (bbdb-display-all-records-completely + arg + (if (not (bbdb-do-all-records-p)) + (list (assq (bbdb-current-record) bbdb-records))))) + +;;;###autoload +(defun bbdb-display-record-with-layout (layout &optional records) + "Show all the fields of the current record using LAYOUT." + (interactive (list (completing-read "Layout: " + (mapcar (lambda (i) + (list (symbol-name (car i)))) + bbdb-display-layout-alist)))) + (when (stringp layout) + (setq layout (intern layout))) + (when (null records) + (setq records bbdb-records)) + (bbdb-change-records-state-and-redisplay layout records)) + +;;;###autoload +(defun bbdb-omit-record (n) + "Remove the current record from the display without deleting it from the +database. With a prefix argument, omit the next N records. If negative, +omit backwards." + (interactive "p") + (while (not (= n 0)) + (if (< n 0) (bbdb-prev-record 1)) + (let* ((record (or (bbdb-current-record) (error "no records"))) + (rest bbdb-records) + cons next prev-tail) + (while rest + (if (eq (car (car rest)) record) + (setq cons (car rest) + next (car (cdr rest)) + rest nil) + (setq prev-tail rest + rest (cdr rest)))) + (or record (error "can't find current record")) + (let ((buffer-read-only nil)) + (delete-region (nth 2 cons) (if next (nth 2 next) (point-max)))) + (if prev-tail + (setcdr prev-tail (cdr (cdr prev-tail))) + (setq bbdb-records (cdr bbdb-records))) + (setq n (if (> n 0) (1- n) (1+ n))))) + (bbdb-frob-mode-line (length bbdb-records))) + +;;; Fixing up bogus entries + +(defcustom bbdb-refile-notes-generate-alist '((creation-date . bbdb-refile-notes-string-least) (timestamp . bbdb-refile-notes-string-most)) + "*An alist defining specific merging function, based on notes field." + :group 'bbdb-noticing-records + :type '(repeat (cons + (symbol :tag "Notes filed") + (hook :tag "Generating function")))) + +(defcustom bbdb-refile-notes-default-merge-function 'bbdb-refile-notes-default-merge-function + "*Default function to use for merging BBDB notes records. + +If the note field has an entry in `bbdb-refile-notes-generate-alist', +that function will be used instead." + :group 'bbdb-noticing-records + :type 'function) + + +(defun bbdb-refile-notes-default-merge-function (string1 string2) + "Returns the concatenation of STRING1 and STRING2" + (concat string1 "\n" string2)) + +(defun bbdb-refile-notes-remove-duplicates (string1 string2) + "Concatenate STRING1 and STRING2, but remove duplicate lines." + (let ((note1 (split-string string1 "\n")) + (note2 (split-string string2 "\n"))) + (while note2 + (if (not (member (car note2) note1)) + (setq note1 (cons (car note2) note1))) + (setq note2 (cdr note2))) + (mapconcat 'identity note1 "\n"))) + +(defun bbdb-refile-notes-string-least (string1 string2) + "Returns the string that is lessp." + (if (string-lessp string1 string2) + string1 + string2)) + +(defun bbdb-refile-notes-string-most (string1 string2) + "Returns the string that is not lessp." + (if (string-lessp string1 string2) + string2 + string1)) + +(defun bbdb-merge-lists! (l1 l2 cmp &optional mod) + "Merge two lists l1 l2 (modifies l1) only adds elements from l2 +if cmp returns false for all elements of l1. If optional mod +is provided it is applied to each element of l1 and l2 prior to cmp" + (if (null l1) + l2 + (let ((end (last l1)) + (src2 l2) + (chk (if mod (mapcar mod l1) (append l1 '())))) + (while src2 + (let ((fail '()) + (src1 chk) + (val (if mod (apply mod (car src2) '()) (car src2)))) + (while src1 + (if (apply cmp (car src1) val '()) + (setq src1 '() + fail 't) + (setq src1 (cdr src1)))) + (if fail '() + (setcdr end (cons (car src2) '())) + (setq end (cdr end))) + (setq src2 (cdr src2)))) + l1))) + +(defun bbdb-merge-records (old-record new-record) + "Merge the contents of old-record into new-record, old-record +remains unchanged. For name and company it queries about which to use +if they differ. All other fields are concatenated. Idealy this would +be better about checking for duplicate entries in other fields, as +well as possibly querying about differing values. + +This function does nothing to ensure the integrity of the rest of the +database, that is somebody elses problem (something like +`bbdb-refile-record')." + (if (or (null new-record) (eq old-record new-record)) + (error "those are the same")) + (let ((new-name (bbdb-record-name new-record)) + (new-co (bbdb-record-company new-record)) + (old-name (bbdb-record-name old-record)) + (old-co (bbdb-record-company old-record)) + (old-nets (bbdb-record-net old-record)) + (old-aka (bbdb-record-aka old-record)) + extra-name) + (let ((name + (cond ((= 0 (length old-name)) + (cons (bbdb-record-firstname new-record) + (bbdb-record-lastname new-record))) + ((= 0 (length new-name)) + (cons (bbdb-record-firstname old-record) + (bbdb-record-lastname old-record))) + ((string-equal (downcase old-name) (downcase new-name)) + (cons (bbdb-record-firstname new-record) + (bbdb-record-lastname new-record))) + (t (prog1 + (if (bbdb-y-or-n-p + (format "Use name \"%s\" instead of \"%s\"? " + old-name new-name)) + (progn + (setq extra-name new-record) + (cons (bbdb-record-firstname old-record) + (bbdb-record-lastname old-record))) + (setq extra-name old-record) + (cons (bbdb-record-firstname new-record) + (bbdb-record-lastname new-record))) + (or (and bbdb-use-alternate-names + (bbdb-y-or-n-p + (format "Keep \"%s\" as an alternate name? " + (bbdb-record-name extra-name)))) + (setq extra-name nil)))))) + (comp (cond ((= 0 (length old-co)) new-co) + ((= 0 (length new-co)) old-co) + ((string-equal old-co new-co) new-co) + (t (if (bbdb-y-or-n-p + (format "Use company \"%s\" instead of \"%s\"? " + old-co new-co)) + old-co new-co))))) + + (if extra-name + (setq old-aka (cons (bbdb-record-name extra-name) old-aka))) + + (bbdb-record-set-phones new-record + (bbdb-merge-lists! + (bbdb-record-phones new-record) + (bbdb-record-phones old-record) + 'equal)) + (bbdb-record-set-addresses new-record + (bbdb-merge-lists! + (bbdb-record-addresses new-record) + (bbdb-record-addresses old-record) + 'equal)) + (bbdb-record-set-company new-record comp) + + (let ((n1 (bbdb-record-raw-notes new-record)) + (n2 (bbdb-record-raw-notes old-record)) + tmp) + (or (equal n1 n2) + (progn + (or (listp n1) (setq n1 (list (cons 'notes n1)))) + (or (listp n2) (setq n2 (list (cons 'notes n2)))) + (while n2 + (if (setq tmp (assq (car (car n2)) n1)) + (setcdr tmp + (funcall + (or (cdr (assq (car (car n2)) + bbdb-refile-notes-generate-alist)) + bbdb-refile-notes-default-merge-function) + (cdr tmp) (cdr (car n2)))) + (setq n1 (nconc n1 (list (car n2))))) + (setq n2 (cdr n2))) + (bbdb-record-set-raw-notes new-record n1)))) + + (bbdb-record-set-firstname new-record (car name)) + (bbdb-record-set-lastname new-record (cdr name)) + (bbdb-record-set-namecache new-record nil) + + (bbdb-record-set-net new-record + (bbdb-merge-lists! + (bbdb-record-net new-record) old-nets + 'string= 'downcase)) + (bbdb-record-set-aka new-record + (bbdb-merge-lists! + (bbdb-record-aka new-record) old-aka + 'string= 'downcase)) + new-record))) + +;;;###autoload +(defun bbdb-refile-record (old-record new-record) + "Merge the current record into some other record; that is, delete the +record under point after copying all of the data within it into some other +record. this is useful if you realize that somehow a redundant record has +gotten into the database, and you want to merge it with another. + +If both records have names and/or companies, you are asked which to use. +Phone numbers, addresses, and network addresses are simply concatenated. +The first record is the record under the point; the second is prompted for. +Completion behaviour is as dictated by the variable `bbdb-completion-type'." + (interactive + (let ((r (bbdb-current-record)) + name) + (setq name (bbdb-record-name r)) + (list r + (if current-prefix-arg + (car (delq r (bbdb-search (bbdb-records) name nil))) + (bbdb-completing-read-one-record + (format "merge record \"%s\" into: " + (or (bbdb-record-name r) (car (bbdb-record-net r)) + "???")) (list r)))))) + + (if (or (null new-record) (eq old-record new-record)) + (error "those are the same")) + (setq new-record (bbdb-merge-records old-record new-record)) + + (bbdb-delete-current-record old-record 'noprompt) + (bbdb-change-record new-record t) ; don't always need-to-sort... + (let ((bbdb-display-layout nil)) + (if (assq new-record bbdb-records) + (bbdb-redisplay-one-record new-record)) + (bbdb-with-db-buffer + (if (not (memq new-record bbdb-changed-records)) + (setq bbdb-changed-records + (cons new-record bbdb-changed-records)))) + (if (null bbdb-records) ; nothing displayed, display something. + (bbdb-display-records (list new-record)))) + (message "records merged.")) + +;; sort the notes +(defcustom bbdb-notes-sort-order + '((notes . 0) (www . 1) (ftp . 2) (gopher . 3) (telnet . 4) (mail-alias . 5) + (mail-folder . 6) (lpr . 7) (creation-date . 1000) (timestamp . 1001)) + "*The order for sorting the notes. +If a note is not in the alist, it is assigned weight 100, so all notes +with weights less then 100 will be in the beginning, and all notes with +weights more than 100 will be in the end." + :group 'bbdb-noticing-records + :type 'list) + +;;;###autoload +(defun bbdb-sort-notes (rec) + "Sort the notes in the record according to `bbdb-notes-sort-order'. +Can be used in `bbdb-change-hook'." + (flet ((kk (nt) (or (cdr (assq (car nt) bbdb-notes-sort-order)) 100))) + (bbdb-record-set-raw-notes + rec (sort (bbdb-record-raw-notes rec) + (lambda (aa bb) (< (kk aa) (kk bb))))))) + +;;;###autoload +(defun bbdb-sort-phones (rec) + "Sort the phones in the record according to the location. +Can be used in `bbdb-change-hook'." + (bbdb-record-set-phones + rec (sort (bbdb-record-phones rec) + (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))) + +;;;###autoload +(defun bbdb-sort-addresses (rec) + "Sort the addresses in the record according to the location. +Can be used in `bbdb-change-hook'." + (bbdb-record-set-addresses + rec (sort (bbdb-record-addresses rec) + (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))) + + +;;; Send-Mail interface + +(defcustom bbdb-dwim-net-address-allow-redundancy nil + "*Non-nil means always use full name when sending mail, even if same as net." + :group 'bbdb + :type '(choice (const :tag "Disallow redundancy" nil) + (const :tag "Return only the net" 'netonly) + (const :tag "Allow redundancy" t))) + +;;;###autoload +(defun bbdb-dwim-net-address (record &optional net) + "Returns a string to use as the email address of the given record. The +given address is the address the mail is destined to; this is formatted like +\"Firstname Lastname \" unless both the first name and last name are +constituents of the address, as in John.Doe@SomeHost, or the address is +already in the form \"Name \" or \"foo (Name)\", in which case the +address is used as-is. If `bbdb-dwim-net-address-allow-redundancy' is non-nil, +the name is always included. If `bbdb-dwim-net-address-allow-redundancy' is +'netonly the name is never included!" + (or net (setq net (car (bbdb-record-net record)))) + (or net (error "record unhas network addresses")) + (let* ((override (bbdb-record-getprop record 'mail-name)) + (name (or override (bbdb-record-name record))) + fn ln (i 0)) + (if override + (let ((both (bbdb-divide-name override))) + (setq fn (car both) + ln (car (cdr both))) + (if (equal fn "") (setq fn nil)) + (if (equal ln "") (setq ln nil))) + (setq fn (bbdb-record-firstname record) + ln (bbdb-record-lastname record))) + ;; if the name contains backslashes or double-quotes, backslash them. + (if name + (while (setq i (string-match "[\\\"]" name i)) + (setq name (concat (substring name 0 i) "\\" (substring name i)) + i (+ i 2)))) + (cond ((eq 'netonly bbdb-dwim-net-address-allow-redundancy) + net) + ((or (null name) + (if (not bbdb-dwim-net-address-allow-redundancy) + (cond ((and fn ln) + (or (string-match + (concat "\\`[^!@%]*\\b" (regexp-quote fn) + "\\b[^!%@]+\\b" (regexp-quote ln) "\\b") + net) + (string-match + (concat "\\`[^!@%]*\\b" (regexp-quote ln) + "\\b[^!%@]+\\b" (regexp-quote fn) "\\b") + net))) + ((or fn ln) + (string-match + (concat "\\`[^!@%]*\\b" (regexp-quote (or fn ln)) "\\b") + net)))) + ;; already in "foo " or "bar " format. + (string-match "\\`[ \t]*[^<]+[ \t]*<" net) + (string-match "\\`[ \t]*[^(]+[ \t]*(" net)) + net) + ;; if the name contains control chars or RFC822 specials, it needs + ;; to be enclosed in quotes. Double-quotes and backslashes have + ;; already been escaped. This quotes a few extra characters as + ;; well (!,%, and $) just for common sense. + ((string-match "[][\000-\037\177()<>@,;:.!$%]" name) + (format "\"%s\" <%s>" name net)) + (t + (format "%s <%s>" name net))))) + + +(defun bbdb-send-mail-internal (&optional to subj records) + (let ((type (or bbdb-send-mail-style + ;; In Emacs, `compose-mail' gets whatever you've + ;; customized as your preferred `mail-user-agent'. + (cond ((fboundp 'compose-mail) 'compose-mail) + ((featurep 'mh-e) 'mh) + ((featurep 'vm) 'vm) + ((featurep 'message) 'message) + ((featurep 'mew) 'mew) + ((featurep 'gnus) 'gnus) + (t 'mail))))) + (cond + ((eq type 'mh) + (or (fboundp 'mh-send) (autoload 'mh-send "mh-e")) + (mh-send to "" (or subj ""))) + ((eq type 'vm) + (cond ((not (fboundp 'vm-mail-internal)) + (load-library "vm") ; 5.32 or later + (or (fboundp 'vm-mail-internal) + (load-library "vm-reply")))) ; 5.31 or earlier + (vm-session-initialization) + (vm-mail-internal nil to subj) + (run-hooks 'vm-mail-hook) + (run-hooks 'vm-mail-mode-hook)) + ((eq type 'message) + (or (fboundp 'message-mail) (autoload 'message-mail "message")) + (message-mail to subj)) + ((or (eq type 'mail) (eq type 'rmail)) + (mail nil to subj)) + ((eq type 'mew) + (or (fboundp 'mew-send) (load-library "mew")) + (mew-send to nil subj)) + ((eq type 'compose-mail) + (compose-mail to subj)) + ((eq type 'gnus) + (gnus-msg-mail to subj)) + (t + (error "bbdb-send-mail-style must be vm, mh, message, compose-mail, or rmail"))))) + +;;;###autoload +(defun bbdb-send-mail (bbdb-record &optional subject) + "Compose a mail message to the person indicated by the current bbdb record. +The first (most-recently-added) address is used if there are more than one. +\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-send-mail]\" is \ +used instead of simply \"\\[bbdb-send-mail]\", then mail will be sent to \ +all of the +folks listed in the *BBDB* buffer instead of just the person at point." + (interactive (list (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (bbdb-current-record)))) + (if (consp bbdb-record) + (bbdb-send-mail-many bbdb-record subject) + (bbdb-send-mail-1 bbdb-record subject))) + + +(defun bbdb-send-mail-1 (bbdb-record &optional subject) + (if bbdb-inside-electric-display + (bbdb-electric-throw-to-execute + (list 'bbdb-send-mail bbdb-record subject))) + ;; else... + + (cond ((null bbdb-record) (error "record unexists")) + ((null (bbdb-record-net bbdb-record)) + (error "Current record unhas a network addresses.")) + (t (bbdb-send-mail-internal (bbdb-dwim-net-address bbdb-record) + subject (list bbdb-record)) + (if (re-search-backward "^Subject: $" nil t) (end-of-line))))) + + +(defun bbdb-send-mail-many (records &optional subject) + (if bbdb-inside-electric-display + (bbdb-electric-throw-to-execute + (list 'bbdb-send-mail (list 'quote records) subject))) + ;; else... + + (let ((good '()) (bad '()) + (orec records)) + (while records + (if (bbdb-record-net (car records)) + (setq good (cons (car records) good)) + (setq bad (cons (car records) bad))) + (setq records (cdr records))) + (bbdb-send-mail-internal + (mapconcat (lambda (x) (bbdb-dwim-net-address x)) + (nreverse good) ",\n ") + subject orec) + (if (not bad) nil + (goto-char (point-max)) + (let ((p (point)) + (fill-prefix " ") + (fill-column 70)) + (insert "*** Warning: No net addresses for " + (mapconcat (lambda (x) (bbdb-record-name x)) + (nreverse bad) ", ") ".") + (fill-region-as-paragraph p (point)) + (goto-char p)))) + (if (re-search-backward "^Subject: $" nil t) (end-of-line))) + + +(defun bbdb-yank-addresses () + "CC the people displayed in the *BBDB* buffer on this message. +The primary net-address of each of the records currently listed in the +*BBDB* buffer (whether it is visible or not) will be appended to the +CC: field of the current buffer (assuming the current buffer is a mail +composition buffer.)" + (interactive) + (let ((addrs (save-excursion + (set-buffer bbdb-buffer-name) + (delq nil + (mapcar (lambda (x) + (if (bbdb-record-net (car x)) + (bbdb-dwim-net-address (car x)) + nil)) + bbdb-records))))) + (goto-char (point-min)) + ;; If there's a CC field, move to the end of it, inserting a comma if + ;; there are already addresses present. + ;; Otherwise, if there's an empty To: field, move to the end of it. + ;; Otherwise, insert an empty CC: field. + (if (re-search-forward "^CC:[ \t]*" nil t) + (if (eolp) + nil + (end-of-line) + (while (looking-at "\n[ \t]") + (forward-char) (end-of-line)) + (insert ",\n") + (indent-relative)) + (re-search-forward "^To:[ \t]*") + (if (eolp) + nil + (end-of-line) + (while (looking-at "\n[ \t]") + (forward-char) (end-of-line)) + (insert ",\n") + (indent-relative)) + (if (eolp) + nil + (end-of-line) + (while (looking-at "\n[ \t]") + (forward-char) (end-of-line)) + (insert "\nCC:") + (indent-relative))) + ;; Now insert each of the addresses on its own line. + (while addrs + (insert (car addrs)) + (if (cdr addrs) (progn (insert ",\n") (indent-relative))) + (setq addrs (cdr addrs))))) + +;;;###autoload +(defun bbdb-show-all-recipients () + "*Display BBDB records for all recipients of the message in this buffer." + (interactive) + (let ((marker (bbdb-header-start)) + (fields '("from" "sender" "to" "cc" "bcc" + "resent-from" "resent-to" "resent-cc" "resent-bcc")) + addrs) + (message "Searching...") + (save-excursion + (set-buffer (marker-buffer marker)) + (while fields + (goto-char marker) + (setq addrs (append (bbdb-split (or (bbdb-extract-field-value + (car fields)) + "") + ",") + addrs) + fields (cdr fields)))) + (let ((rest addrs) + (records '()) + record) + (while rest + (setq record (bbdb-annotate-message-sender (car rest) t t t)) + (if record (setq records (cons record records))) + (setq rest (cdr rest))) + (message "Sorting...") + (setq records (sort records (lambda (x y) (bbdb-record-lessp x y)))) + (bbdb-display-records records)))) + + +;;; completion + +;;;###autoload +(defun bbdb-completion-check-record (sym rec) + (let ((name (or (bbdb-record-name rec) + (bbdb-record-company rec) + "")) + (nets (bbdb-record-net rec)) + ok) + + (if (null bbdb-completion-type) + (setq ok 't) + + (if (memq bbdb-completion-type + '(name primary-or-name name-or-primary)) + (setq ok (string= sym (downcase name)))) + + ;; #### handle AKA, mail-name or mail-alias here? + (if ok '() + (when (eq bbdb-completion-type 'net) + (while (and nets (not ok)) + (setq ok (string= sym (downcase (car nets))) + nets (cdr nets)))) + (when (and nets (memq bbdb-completion-type + '(primary primary-or-name name-or-primary))) + (setq ok (string= sym (downcase (car nets))))))) + ok)) + + +;;;###autoload +(defun bbdb-completion-predicate (symbol) + "For use as the third argument to `completing-read'. +Obey the semantics of `bbdb-completion-type'." + (cond ((null bbdb-completion-type) + t) + ((not (boundp symbol)) + nil) + (t + (let ((sym (symbol-name symbol)) + (recs (symbol-value symbol)) + ok) + (while (and recs (not ok)) + (setq ok (bbdb-completion-check-record sym (car recs)) + recs (cdr recs))) + ok)))) + +(defun bbdb-completing-read-record (prompt &optional omit-records) + "Prompt for and return a record from the bbdb. +Completion is done according to `bbdb-completion-type'. If the user +just hits return, nil is returned. Otherwise, a valid response is forced." + (let* ((ht (bbdb-hashtable)) + (completion-ignore-case 't) + (string (completing-read prompt ht 'bbdb-completion-predicate t)) + (symbol (and (not (= 0 (length string))) + (intern-soft string ht)))) + (if symbol + (if (and (boundp symbol) (symbol-value symbol)) + (let ((recs (symbol-value symbol)) ret) + (while recs + (if (and (not (memq (car recs) omit-records)) + (bbdb-completion-check-record (symbol-name symbol) + (car recs))) + (setq ret (cons (car recs) ret))) + (setq recs (cdr recs))) + ret) + (error "selecting deleted (unhashed) record \"%s\"!" symbol)) + nil))) + +(defun bbdb-completing-read-one-record (prompt &optional omit-records) + "Prompt for and return a single record from the bbdb; +completion is done according to `bbdb-completion-type'. If the user +just hits return, nil is returned. Otherwise, a valid response is forced. +if omit-records is non-nil it should be a list of records to dis-allow +completion with." + (let ((records (bbdb-remove-memq-duplicates + (bbdb-completing-read-record prompt omit-records)))) + (cond + ((eq (length records) 1) + (car records)) + ((> (length records) 1) + (let ((count (length records)) + prompts result) + (bbdb-display-records records) + (while (> count 0) + (setq prompts (cons (list (number-to-string count) count) prompts) + count (1- count))) + (setq result + (completing-read (format "Which duplicate record (1-%s): " + (length records)) + prompts nil t "1")) + (nth (1- (string-to-number result)) records))) + (t + nil)))) + +(defvar bbdb-read-addresses-with-completion-map + (let ((map (copy-keymap minibuffer-local-completion-map))) + (define-key map " " 'self-insert-command) + (define-key map "\t" 'bbdb-complete-name) + (define-key map "\M-\t" 'bbdb-complete-name) + map)) + +;;;###autoload +(defun bbdb-read-addresses-with-completion (prompt &optional default) + "Like `read-string', but allows `bbdb-complete-name' style completion." + (read-from-minibuffer prompt default + bbdb-read-addresses-with-completion-map)) + + +;; Internal use. Store the window configuration before we pop up the +;; completion buffer. +(defvar bbdb-complete-name-saved-window-config nil) + +;; Restore the saved window configuration +(defun bbdb-complete-name-cleanup () + (if bbdb-complete-name-saved-window-config + (progn + (if (get-buffer-window "*Completions*") + (progn + (set-window-configuration + bbdb-complete-name-saved-window-config) + (bury-buffer "*Completions*")) + ) + (setq bbdb-complete-name-saved-window-config nil)))) + +(defun bbdb-display-completion-list (list &optional callback data) + "Wrapper for `display-completion-list'. +GNU Emacs requires DATA to be in a specific format, viz. (nth 1 data) should +be a marker for the start of the region being completed." + (if (featurep 'xemacs) + (display-completion-list list :activate-callback callback + :user-data data) + (display-completion-list list) + ;; disgusting hack to make GNU Emacs nuke the bit you've typed + ;; when it inserts the completion. + (if data + (save-excursion + (set-buffer standard-output) + (setq completion-base-size + (- (marker-position (nth 1 data)) 1)))))) + +(defun bbdb-complete-clicked-name (event extent user-data) + "Find the record for a name clicked in a completion buffer. +Currently only used by XEmacs." + (let ((buffer (nth 0 user-data)) + (bbdb-complete-name-allow-cycling nil) + (beg (nth 1 user-data)) + (end (nth 2 user-data))) + (bbdb-complete-name-cleanup) + (set-buffer buffer) + (goto-char beg) + (delete-region beg end) + (insert (bbdb-extent-string extent)) + (bbdb-complete-name beg))) + + +(defun bbdb-list-overlap (l1 l2) + (let (ok) + (while (and (not ok) l1) + (if (memq (car l1) l2) (setq ok t l1 '()) + (setq l1 (cdr l1)))) + ok)) + +(defun bbdb-remove-assoc-duplicates (l) + (if (null l) '() + (if (assoc (car (car l)) (cdr l)) + (bbdb-remove-assoc-duplicates (cdr l)) + (cons (car l) (bbdb-remove-assoc-duplicates (cdr l)))))) + +(defcustom bbdb-complete-name-allow-cycling nil + "Whether to allow cycling of email addresses when calling +`bbdb-complete-name' on a completed address in a composition buffer." + :group 'bbdb-mua-specific + :type 'boolean) + +(defcustom bbdb-complete-name-hooks nil + "List of functions called after a sucessful completion." + :group 'bbdb-mua-specific + :type 'boolean) + +(eval-when-compile (defvar auto-fill-hook)) + +;;;###autoload +(defun bbdb-complete-name (&optional start-pos) + "Complete the user full-name or net-address before point (up to the +preceeding newline, colon, or comma, or the value of START-POS). If +what has been typed is unique, insert an entry of the form \"User Name +\" (although see documentation for +bbdb-dwim-net-address-allow-redundancy). If it is a valid completion +but not unique, a list of completions is displayed. + +If the completion is done and `bbdb-complete-name-allow-cycling' is +true then cycle through the nets for the matching record. + +When called with a prefix arg then display a list of all nets. + +Completion behaviour can be controlled with `bbdb-completion-type'." + (interactive) + + (let* ((end (point)) + (beg (or start-pos + (save-excursion + (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*") + (goto-char (match-end 0)) + (point)))) + (orig (buffer-substring beg end)) + (typed (downcase orig)) + (pattern (bbdb-string-trim typed)) + (ht (bbdb-hashtable)) + ;; make a list of possible completion strings + ;; (all-the-completions), and a flag to indicate if there's a + ;; single matching record or not (only-one-p) + (only-one-p t) + (all-the-completions nil) + (pred + (lambda (sym) + (when (bbdb-completion-predicate sym) + (if (and only-one-p + all-the-completions + (or + ;; not sure about this. more than one record + ;; attached to the symbol? does that happen? + (> (length (symbol-value sym)) 1) + ;; this is the doozy, though. multiple syms + ;; which all match the same record + (delete t (mapcar (lambda(x) + (equal (symbol-value x) + (symbol-value sym))) + all-the-completions)))) + (setq only-one-p nil)) + (if (not (memq sym all-the-completions)) + (setq all-the-completions (cons sym all-the-completions)))))) + (completion (try-completion pattern ht pred)) + (exact-match (eq completion t))) + + (cond + ;; No matches found OR you're trying completion on an + ;; already-completed record. In the latter case, we might have to + ;; cycle through the nets for that record. + ((or (null completion) + (and bbdb-complete-name-allow-cycling + exact-match ;; which is a net of the record + (member orig + (bbdb-record-net + (car (symbol-value (intern-soft pattern ht))))))) + ;; Clean up the completion buffer, if it exists + (bbdb-complete-name-cleanup) + ;; Check for cycling + (or (catch 'bbdb-cycling-exit + ;; jump straight out if we're not cycling + (or bbdb-complete-name-allow-cycling + (throw 'bbdb-cycling-exit nil)) + + ;; find the record we're working on. + (let* ((addr (funcall bbdb-extract-address-components-func orig)) + (rec + (if (listp addr) + ;; for now, we're ignoring the case where this + ;; returns more than one record. Ideally, the + ;; last expansion would be stored in a + ;; buffer-local variable, perhaps. + (car (bbdb-search-intertwingle (caar addr) + (cadar addr))) + nil))) + (or rec + (throw 'bbdb-cycling-exit nil)) + + (if current-prefix-arg + ;; use completion buffer + (let ((standard-output (get-buffer-create "*Completions*"))) + ;; a previously existing buffer has to be cleaned first + (save-excursion (set-buffer standard-output) + (setq buffer-read-only nil) + (erase-buffer)) + (display-completion-list + (mapcar (lambda (n) (bbdb-dwim-net-address rec n)) + (bbdb-record-net rec))) + (delete-region beg end) + (switch-to-buffer standard-output)) + ;; use next address + (let* ((addrs (bbdb-record-net rec)) + (this-addr (or (cadr (member (car (cdar addr)) addrs)) + (nth 0 addrs)))) + (if (= (length addrs) 1) + ;; no alternatives. don't signal an error. + (throw 'bbdb-cycling-exit t) + ;; replace with new mail address + (delete-region beg end) + (insert (bbdb-dwim-net-address rec this-addr)) + (run-hooks 'bbdb-complete-name-hooks) + (throw 'bbdb-cycling-exit t)))))) + + ;; FALL THROUGH + ;; Check mail aliases + (if (and bbdb-expand-mail-aliases (expand-abbrev)) + () + (when bbdb-complete-name-hooks + (message "completion for \"%s\" unfound." pattern) + (ding)))));; no matches, sorry! + + ;; Match for a single record. If cycling is enabled then we don't + ;; care too much about the exact-match part. + ((and only-one-p (or exact-match bbdb-complete-name-allow-cycling)) + (let* ((sym (if exact-match (intern-soft pattern ht) (car all-the-completions))) + (recs (symbol-value sym)) + the-net match-recs lst primary matched) + + (while recs + (when (bbdb-record-net (car recs)) + + ;; Did we match on name? + (let ((b-r-name (or (bbdb-record-name (car recs)) ""))) + (if (string= pattern + (substring (downcase b-r-name) 0 + (min (length b-r-name) + (length pattern)))) + (setq match-recs (cons (car recs) match-recs) + matched t))) + + ;; Did we match on aka? + (when (not matched) + (setq lst (bbdb-record-aka (car recs))) + (while lst + (if (string= pattern (substring (downcase (car lst)) 0 + (min (length (downcase + (car + lst))) + (length pattern)))) + (setq match-recs (append match-recs (list (car recs))) + matched t + lst '()) + (setq lst (cdr lst))))) + + ;; Name didn't match name so check net matching + (when (not matched) + (setq lst (bbdb-record-net (car recs))) + (setq primary t) ;; primary wins over secondary... + (while lst + (if (string= pattern (substring (downcase (car lst)) + 0 (min (length + (downcase (car + lst))) + (length pattern)))) + (setq the-net (car lst) + lst nil + match-recs + (if primary (cons (car recs) match-recs) + (append match-recs (list (car recs)))))) + (setq lst (cdr lst) + primary nil)))) + + ;; loop to next rec + (setq recs (cdr recs) + matched nil)) + + (unless match-recs + (error "only exact matching record unhas net field")) + + ;; now replace the text with the expansion + (delete-region beg end) + (insert (bbdb-dwim-net-address (car match-recs) the-net)) + + ;; if we're past fill-column, wrap at the previous comma. + (if (and + (bbdb-auto-fill-function) + (>= (current-column) fill-column)) + (let ((p (point)) + bol) + (save-excursion + (beginning-of-line) + (setq bol (point)) + (goto-char p) + (if (search-backward "," bol t) + (progn + (forward-char 1) + (insert "\n ")))))) + + ;; Update the *BBDB* buffer if desired. + (if bbdb-completion-display-record + (let ((bbdb-gag-messages t)) + (bbdb-pop-up-bbdb-buffer) + (bbdb-display-records-1 match-recs t))) + (bbdb-complete-name-cleanup) + + ;; call the exact-completion hook + (run-hooks 'bbdb-complete-name-hooks))) + + ;; Partial match + ;; note, we can't use the trimmed version of the pattern here or + ;; we'll recurse infinitely on e.g. common first names + ((and (stringp completion) (not (string= typed completion))) + (delete-region beg end) + (insert completion) + (setq end (point)) + (let ((last "") + (bbdb-complete-name-allow-cycling nil)) + (while (and (stringp completion) + (not (string= completion last)) + (setq last completion + pattern (downcase orig) + completion (try-completion pattern ht pred))) + (if (stringp completion) + (progn (delete-region beg end) + (insert completion)))) + (bbdb-complete-name beg))) + + ;; Exact match, but more than one record + (t + (or (eq (selected-window) (minibuffer-window)) + (message "Making completion list...")) + + (let (dwim-completions + uniq nets net name akas) + ;; Now collect all the dwim-addresses for each completion, but only + ;; once for each record! Add it if the net is part of the completions + (bbdb-mapc + (lambda (sym) + (bbdb-mapc + (lambda (rec) + (when (not (member rec uniq)) + (setq uniq (cons rec uniq) + nets (bbdb-record-net rec) + name (downcase (or (bbdb-record-name rec) "")) + akas (mapcar 'downcase (bbdb-record-aka rec))) + (while nets + (setq net (car nets)) + (when (cond + ;; primary + ((and (member bbdb-completion-type + '(primary primary-or-name)) + (member (intern-soft (downcase net) ht) + all-the-completions)) + (setq nets nil) + t) + ;; name + ((and name (member bbdb-completion-type + '(nil name primary-or-name)) + (let ((cname (symbol-name sym))) + (or (string= cname name) + (member cname akas)))) + (setq name nil) + t) + ;; net + ((and (member bbdb-completion-type + '(nil net)) + (member (intern-soft (downcase net) ht) + all-the-completions))) + ;; (name-or-)primary + ((and (member bbdb-completion-type + '(name-or-primary)) + (let ((cname (symbol-name sym))) + (or (string= cname name) + (member cname akas)))) + (setq nets nil) + t) + ) + (setq dwim-completions + (cons (bbdb-dwim-net-address rec net) + dwim-completions)) + (if exact-match (setq nets nil))) + (setq nets (cdr nets))))) + (symbol-value sym))) + all-the-completions) + + ;; if, after all that, we've only got one matching record... + (if (and dwim-completions (null (cdr dwim-completions))) + (progn + (delete-region beg end) + (insert (car dwim-completions)) + (message "")) + ;; otherwise, pop up a completions window + (if (not (get-buffer-window "*Completions*")) + (setq bbdb-complete-name-saved-window-config + (current-window-configuration))) + (let ((arg (list (current-buffer) + (set-marker (make-marker) beg) + (set-marker (make-marker) end)))) + (with-output-to-temp-buffer "*Completions*" + (bbdb-display-completion-list + dwim-completions + 'bbdb-complete-clicked-name + arg))) + (or (eq (selected-window) (minibuffer-window)) + (message "Making completion list...done")))))))) + +;;;###autoload +(defun bbdb-yank () + "Insert the current contents of the *BBDB* buffer at point." + (interactive) + (insert (let ((b (current-buffer))) + (set-buffer bbdb-buffer-name) + (prog1 (buffer-string) (set-buffer b))))) + + +;;; interface to mail-abbrevs.el. + +(defcustom bbdb-define-all-aliases-field 'mail-alias + "*The field which `bbdb-define-all-aliases' searches for." + :group 'bbdb + :type 'symbol) + +(defcustom bbdb-define-all-aliases-mode 'first + "*The type of alias which are created. +first: Default is to generate an abbrev which is \"alias\" and expands to the + primary net. +star: Generate an extra alias \"*\" which expands to all nets of an + record. +all: Generate an alias all nets (as for 'star) and an alias for each net + as \"n\" where n is the position of the net in the nets of the + record." + :group 'bbdb + :type '(choice (symbol :tag "Only first" first) + (symbol :tag "* for all nets" star) + (symbol :tag "All aliases" all))) + +;;;###autoload +(defun bbdb-define-all-aliases () + "Define mail aliases for some of the records in the database. +Every record which has a `mail-alias' field will have a mail alias +defined for it which is the contents of that field. If there are +multiple comma-separated words in the `mail-alias' field, then all +of those words will be defined as aliases for that person. + +If multiple entries in the database have the same mail alias, then +that alias expands to a comma-separated list of the network addresses +of all of those people." + (interactive "") + (let* ((target (cons bbdb-define-all-aliases-field ".")) + (use-abbrev-p (fboundp 'define-mail-abbrev)) + (mail-alias-separator-string (if (boundp 'mail-alias-separator-string) + mail-alias-separator-string + ", ")) + (records (bbdb-search (bbdb-records) nil nil nil target)) + result record aliases match) + + (if use-abbrev-p + nil + ;; clear abbrev-table + (setq mail-aliases nil) + ;; arrange rebuilt if necessary, this should be done by + ;; mail-pre-abbrev-expand-hook, but there is none! + (defadvice sendmail-pre-abbrev-expand-hook + (before bbdb-rebuilt-all-aliases activate) + (bbdb-rebuilt-all-aliases))) + + ;; collect an alist of (alias rec1 [rec2 ...]) + (while records + (setq record (car records)) + (if (bbdb-record-net record) + (setq aliases (bbdb-split + (bbdb-record-getprop record + bbdb-define-all-aliases-field) + ",")) + (if (not bbdb-silent-running) + (bbdb-warn "record %S has no network address, but the aliases: %s" + (bbdb-record-name record) + (bbdb-record-getprop record + bbdb-define-all-aliases-field))) + (setq aliases nil)) + + (while aliases + (if (setq match (assoc (car aliases) result)) + (nconc match (cons record nil)) + (setq result (cons (list (car aliases) record) result))) + (setq aliases (cdr aliases))) + (setq records (cdr records))) + + ;; iterate over the results and create the aliases + (while result + (let* ((aliasstem (caar result)) + (rec (cadar result)) + (group-alias-p (cddar result)) + (nets (if (not group-alias-p) (bbdb-record-net rec))) + (expansions + (if group-alias-p + (mapcar (lambda (r) (bbdb-dwim-net-address r)) (cdar result)) + (mapcar (lambda (net) (bbdb-dwim-net-address rec net)) + (if (eq 'all bbdb-define-all-aliases-mode) + nets + (list (car nets)))))) + (count 1) + alias expansion) + + (if group-alias-p + ;; for group aliases we just take all the primary nets and define + ;; just one expansion! + (setq expansions (list (mapconcat 'identity expansions + mail-alias-separator-string))) + ;; this is an alias for a single person so deal with it according to + ;; the bbdb-define-all-aliases-mode + (when (or (not (eq 'first bbdb-define-all-aliases-mode)) + (setq expansions + (cons (mapconcat 'identity + (mapcar (lambda (net) + (bbdb-dwim-net-address + rec net)) + nets) + mail-alias-separator-string) + expansions) + count 0)))) + + ;; create the aliases for each expansion + (while expansions + (cond ((= count 0);; all the nets of a record + (setq alias (concat aliasstem "*"))) + ((= count 1);; expansion as usual + (setq alias aliasstem)) + (t;; alias# for each net of a record + (setq alias (format "%s%s" aliasstem count)))) + (setq count (1+ count)) + (setq expansion (car expansions)) + + (if use-abbrev-p + (define-mail-abbrev alias expansion) + (define-mail-alias alias expansion)) + (setq alias (or (intern-soft (downcase alias) + (if use-abbrev-p + mail-abbrevs mail-aliases)) + (error "couldn't find the alias we just defined!"))) + + (or (eq (symbol-function alias) 'mail-abbrev-expand-hook) + (error "mail-aliases contains unexpected hook %s" + (symbol-function alias))) + ;; The abbrev-hook is called with network addresses instead of bbdb + ;; records to avoid keeping pointers to records, which would lose if + ;; the database was reverted. It uses -search-simple to convert + ;; these to records, which is plenty fast. + (fset alias (list 'lambda '() + (list 'bbdb-mail-abbrev-expand-hook + alias + (list 'quote + (mapcar (lambda (x) + (car (bbdb-record-net x))) + (cdr (car result))))))) + (setq expansions (cdr expansions)))) + (setq result (cdr result))) + + (when (not use-abbrev-p) + (modify-syntax-entry ?* "w" mail-mode-header-syntax-table) + (sendmail-pre-abbrev-expand-hook)))) + +;; We should be cleverer here and instead of rebuilding all aliases we should +;; just do what's necessary, i.e. remove deleted records and add new records +(defun bbdb-rebuilt-all-aliases () + (let ((needs-rebuilt bbdb-define-all-aliases-needs-rebuilt)) + (when needs-rebuilt + (if (not bbdb-silent-running) + (message "Rebuilding aliases due to %s aliases." needs-rebuilt)) + (setq bbdb-define-all-aliases-needs-rebuilt nil) + (bbdb-define-all-aliases)))) + +(defcustom bbdb-mail-abbrev-expand-hook nil + "*Hook or hooks invoked each time an alias is expanded. +The hook is called with two arguments the alias and the list of records." + :group 'bbdb-hooks + :type 'hook) + +(defun bbdb-mail-abbrev-expand-hook (alias records) + (run-hook-with-args 'bbdb-mail-abbrev-expand-hook alias records) + (mail-abbrev-expand-hook) + (when bbdb-completion-display-record + (if bbdb-use-pop-up + (bbdb-pop-up-bbdb-buffer)) + (let ((bbdb-gag-messages t)) + (bbdb-display-records-1 + (mapcar (lambda (x) (bbdb-search-simple nil x)) records) + t)))) + +(defun bbdb-get-mail-aliases () + "Return a list of mail aliases used in the BBDB. +The format is suitable for `completing-read'." + (let* ((target (cons bbdb-define-all-aliases-field ".")) + (records (bbdb-search (bbdb-records) nil nil nil target)) + result aliases) + (while records + (setq aliases (bbdb-split + (bbdb-record-getprop (car records) + bbdb-define-all-aliases-field) + ",")) + (while aliases + (add-to-list 'result (list (car aliases))) + (setq aliases (cdr aliases))) + (setq records (cdr records))) + result)) + +;;;###autoload +(defun bbdb-add-or-remove-mail-alias (&optional records newalias delete) + "Add NEWALIAS in all RECORDS or remove it if DELETE it t. +When called with prefix argument it will remove the alias. +We honor `bbdb-apply-next-command-to-all-records'! +The new alias will only be added if it isn't there yet." + (interactive (list (if (bbdb-do-all-records-p) 'all 'one) + (completing-read + (format "%s mail alias: " (if current-prefix-arg "Remove" "Add")) + (bbdb-get-mail-aliases)) + current-prefix-arg)) + (setq newalias (bbdb-string-trim newalias)) + (setq newalias (if (string= "" newalias) nil newalias)) + (let* ((propsym bbdb-define-all-aliases-field) + (do-all-p (if (equal records 'one) nil t)) + (records (cond ((equal records 'all) (mapcar 'car bbdb-records)) + ((equal records 'one) (list (bbdb-current-record t))) + (t records)))) + (while records + (let* ((record (car records)) + (oldaliases (bbdb-record-getprop record propsym))) + (if oldaliases (setq oldaliases (bbdb-split oldaliases ","))) + (if delete (setq oldaliases (delete newalias oldaliases)) + (add-to-list 'oldaliases newalias)) + (setq oldaliases (bbdb-join oldaliases ", ")) + (bbdb-record-putprop record propsym oldaliases)) + (setq records (cdr records))) + (if do-all-p + (bbdb-redisplay-records) + (bbdb-redisplay-one-record (bbdb-current-record)))) + (setq bbdb-define-all-aliases-needs-rebuilt + (if delete + 'deleted + (if (bbdb-record-net (bbdb-current-record)) + 'new + nil)))) + +;;; Dialing numbers from BBDB +(defcustom bbdb-dial-local-prefix-alist + '(((if (integerp bbdb-default-area-code) + (format "(%03d)" bbdb-default-area-code) + (or bbdb-default-area-code "")) + "")) + "Mapping to remove local prefixes from numbers. +If this is non-nil, it should be an alist of +(PREFIX REPLACEMENT) elements. The first part of a phone number +matching the regexp returned by evaluating PREFIX will be replaced by +the corresponding REPLACEMENT when dialing." + :group 'bbdb-phone-dialing + :type 'sexp) + +(defcustom bbdb-dial-local-prefix nil + "Local prefix digits. +If this is non-nil, it should be a string of digits which your phone +system requires before making local calls (for example, if your phone system +requires you to dial 9 before making outside calls.) In BBDB's +opinion, you're dialing a local number if it starts with a 0 after +processing bbdb-dial-local-prefix-alist." + :group 'bbdb-phone-dialing + :type '(choice (const :tag "No digits required" nil) + (string :tag "Dial this first" "9"))) + +(defcustom bbdb-dial-long-distance-prefix nil + "Long distance prefix digits. +If this is non-nil, it should be a string of digits which your phone +system requires before making a long distance call (one not in your local +area code). For example, in some areas you must dial 1 before an area +code. Note that this is used to replace the + sign in phone numbers +when dialling (international dialing prefix.)" + :group 'bbdb-phone-dialing + :type '(choice (const :tag "No digits required" nil) + (string :tag "Dial this first" "1"))) + +(defcustom bbdb-sound-player nil + "The program to be used to play the sounds for the touch-tone digits." + :group 'bbdb-phone-dialing + :type '(choice (const :tag "No External Player" nil) + (file :tag "Sound Player" "/usr/local/bin/play"))) + +(defcustom bbdb-sound-files + '["/usr/demo/SOUND/sounds/touchtone.0.au" + "/usr/demo/SOUND/sounds/touchtone.1.au" + "/usr/demo/SOUND/sounds/touchtone.2.au" + "/usr/demo/SOUND/sounds/touchtone.3.au" + "/usr/demo/SOUND/sounds/touchtone.4.au" + "/usr/demo/SOUND/sounds/touchtone.5.au" + "/usr/demo/SOUND/sounds/touchtone.6.au" + "/usr/demo/SOUND/sounds/touchtone.7.au" + "/usr/demo/SOUND/sounds/touchtone.8.au" + "/usr/demo/SOUND/sounds/touchtone.9.au" + "/usr/demo/SOUND/sounds/touchtone.pound.au" + "/usr/demo/SOUND/sounds/touchtone.star.au"] + "A vector of ten sound files to be used for dialing. They +correspond to the 0, 1, 2, ... 9 digits, pound and star, respectively." + :group 'bbdb-phone-dialing + :type 'vector) + +(defcustom bbdb-modem-dial nil + "Type of dialing to use. +If this value is nil, the audio device is used for dialing. Otherwise, +this string is fed to the modem before the phone number digits." + :group 'bbdb-phone-dialing + :type '(choice (const :tag "audio" nil) + (string :tag "tone dialing" "ATDT ") + (string :tag "pulse dialing" "ATDP "))) + +(defcustom bbdb-modem-device "/dev/modem" + "The name of the modem device. +This is only used if bbdb-modem-dial is set to something other than nil." + :group 'bbdb-phone-dialing + :type 'string) + +(defcustom bbdb-sound-volume 50 + "The volume to play back dial tones at. The range is 0 to 100. +This is only used if bbdb-modem-dial is set to nil." + :group 'bbdb-phone-dialing + :type 'integer) + +(defun bbdb-play-sound (num &optional volume) + "Play the specified touchtone number NUM at VOLUME. +Uses external program `bbdb-sound-player' if set, otherwise +try to use internal sound if available." + (if (and (not bbdb-sound-player) (featurep 'native-sound)) + ;; This requires the sound files to be loaded via bbdb-xemacs. + (funcall 'play-sound (intern (format "touchtone%d" num)) + bbdb-sound-volume) + (if (and (not (featurep 'xemacs)) + ;; We can't tell a priori if Emacs 21 facility will + ;; actually work. + (condition-case nil + (play-sound (list 'sound + :file (aref bbdb-sound-files + (string-to-int num)) + :volume (or volume bbdb-sound-volume))) + (error nil))) + (if (and bbdb-sound-player + (file-exists-p bbdb-sound-player)) + (call-process bbdb-sound-player nil nil nil + (aref bbdb-sound-files num)) + (error "BBDB has no means of playing sound."))))) + +(eval-and-compile + (if (fboundp 'next-event) + (fset 'bbdb-next-event 'next-event) + (fset 'bbdb-next-event 'read-event))) + +(defun bbdb-dial-number (phone-string) + "Dial the number specified by PHONE-STRING. +The number is dialed either by playing touchtones through the audio +device using bbdb-sound-player, or by sending a dial sequence to +bbdb-modem-device. # and * are dialed as-is, and a space is treated as +a pause in the dial sequence." + (interactive "sDial number: ") + (let ((dialed "")) + (mapcar + (lambda(d) + (if bbdb-modem-dial + (setq dialed + (concat dialed + (cond ((eq ? d) ",") + ((memq d '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?* ?#)) + (format "%c" d)) + (t "")))) + (cond + ((eq ?# d) + (bbdb-play-sound 10)) + ((eq ?* d) + (bbdb-play-sound 11)) + ((eq ? d) + ;; if we use sit-for, the user can interrupt! + (sleep-for 1)) ;; configurable? + ((memq d '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) + (bbdb-play-sound (- (char-int d) (char-int ?0)))) + (t)))) phone-string) + + ;; tell the user that we're dialed, if we're using the modem + (if bbdb-modem-dial + (with-temp-buffer + (insert bbdb-modem-dial dialed ";\r\n") + (write-region (point-min) (point-max) bbdb-modem-device t) + (message "%s dialed. Pick up the phone now and hit any key ..." + phone-string) + (bbdb-next-event) + (erase-buffer) + (insert "ATH\r\n") + (write-region (point-min) (point-max) bbdb-modem-device t))))) + +;;;###autoload +(defun bbdb-dial (phone force-area-code) + "Dial the number at point. +If the point is at the beginning of a record, dial the first +phone number. Does not dial the extension. Does not apply the +transformations from bbdb-dial-local-prefix-alist if a prefix arg +is given." + (interactive (list (bbdb-current-field) + current-prefix-arg)) + (if (eq (car-safe phone) 'name) + (setq phone (car (bbdb-record-phones (bbdb-current-record))))) + (if (eq (car-safe phone) 'phone) + (setq phone (car (cdr phone)))) + (or (vectorp phone) (error "not on a phone field")) + + (let* ((number (bbdb-phone-string phone)) shortnumber) + (when (not force-area-code) + (let ((alist bbdb-dial-local-prefix-alist)) + (while alist + (if (string-match (concat "^" (eval (caar alist))) number) + (setq shortnumber (concat (car (cdar alist)) + (substring number (match-end 0))) + alist nil)) + (setq alist (cdr alist))))) + + ;; cut off the extension + (if (string-match "x[0-9]+$" number) + (setq number (substring number 0 (match-beginning 0)))) + + ;; This is terrifically Americanized... + ;; Leading 0 => local number (?) + (if (and (not shortnumber) bbdb-dial-local-prefix + (string-match "^0" number)) + (setq number (concat bbdb-dial-local-prefix number))) + + ;; Leading + => long distance/international number + (if (and (not shortnumber) bbdb-dial-long-distance-prefix + (string-match "^\+" number)) + (setq number (concat bbdb-dial-long-distance-prefix " " + (substring number 1)))) + + ;; use the short number if it's available + (setq number (or shortnumber number)) + (if (not bbdb-silent-running) + (message "Dialing %s" number)) + (bbdb-dial-number number))) + + +;; not sure what this is doing here... +(defun bbdb-get-record (prompt) + "Get the current record or ask the user. +To be used in `interactive' like this: +(interactive (list (bbdb-get-record \"look up ...\")))" + (if (and (boundp 'bbdb-buffer-name) +(string= bbdb-buffer-name (buffer-name))) +(bbdb-current-record) +(let (re (pr "")) + (while (not re) + (setq re (bbdb-completing-read-record (concat pr prompt))) + (unless re (ding)) (setq pr "Invalid response! ")) re))) + +;;; Finger, based on code by Sam Cramer . +;;; Note that process-death bugs in 18.57 may make this eat up all the cpu... + +(defcustom bbdb-finger-buffer-name "*finger*" + "The buffer into which finger output should be directed." + :group 'bbdb-utilities-finger + :type 'string) + +(defun bbdb-finger-internal (address) + (message "Fingering %s..." address) + (condition-case condition + (let* ((@ (string-match "@" address)) + (stream (open-network-stream + "finger" bbdb-finger-buffer-name + (if @ (substring address (1+ @)) "localhost") + "finger"))) + (set-process-sentinel stream 'bbdb-finger-process-sentinel) + (princ (concat "finger " address "\n")) + (process-send-string + stream (concat;;"/W " ; cs.stanford.edu doesn't like this... + (if @ (substring address 0 @) address) "\n")) + (process-send-eof stream)) + (error + (princ (format "error fingering %s: %s\n" address + (if (stringp condition) condition + (concat "\n" (nth 1 condition) + (if (cdr (cdr condition)) ": ") + (mapconcat '(lambda (x) + (if (stringp x) x + (prin1-to-string x))) + (cdr (cdr condition)) ", "))))) + (bbdb-finger-process-sentinel nil nil)))) ; hackaroonie + +(defvar bbdb-remaining-addrs-to-finger) +(defun bbdb-finger-process-sentinel (process s) + (save-excursion + (set-buffer bbdb-finger-buffer-name) + (goto-char (point-min)) + (while (search-forward "\r" nil t) + (delete-char -1)) + (if (and (boundp 'bbdb-remaining-addrs-to-finger) + bbdb-remaining-addrs-to-finger) + (let ((addr (car bbdb-remaining-addrs-to-finger))) + (setq bbdb-remaining-addrs-to-finger + (cdr bbdb-remaining-addrs-to-finger)) + (goto-char (point-max)) + (let ((standard-output (current-buffer))) + (princ "\n\n\^L\n") + (bbdb-finger-internal addr))) + (goto-char (point-max)) + (message "Finger done.")))) + +(defcustom bbdb-finger-host-field 'finger-host + "*The field for special net addresses used by \"\\[bbdb-finger]\"." + :group 'bbdb-utilities-finger + :type 'symbol) + +(defun bbdb-record-finger-host (record) + (let ((finger-host (and bbdb-finger-host-field + (bbdb-record-getprop record bbdb-finger-host-field)))) + (if finger-host + (bbdb-split finger-host ",") + (bbdb-record-net record)))) + +;;;###autoload +(defun bbdb-finger (record &optional which-address) + "Finger the network address of a BBDB record. +If this command is executed from the *BBDB* buffer, finger the network +address of the record at point; otherwise, it prompts for a user. +With a numeric prefix argument, finger the Nth network address of the +current record\; with a prefix argument of ^U, finger all of them. +The *finger* buffer is filled asynchronously, meaning that you don't +have to wait around for it to finish\; but fingering another user before +the first finger has finished could have unpredictable results. +\\ +If this command is executed from the *BBDB* buffer, it may be prefixed +with \"\\[bbdb-apply-next-command-to-all-records]\" \(as in \ +\"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-finger]\" instead of \ +simply \"\\[bbdb-finger]\"\), meaning to finger all of +the users currently listed in the *BBDB* buffer instead of just the one +at point. The numeric prefix argument has the same interpretation. + +You can define a special network address to \"finger\" by defining a +field `finger-host' (default value of `bbdb-finger-host-field')." + (interactive (list (bbdb-get-record "BBDB Finger: ") + current-prefix-arg)) + (if (not (consp record)) (setq record (list record))) + (let ((addrs nil)) + (while record + (cond ((null which-address) + (setq addrs + (nconc addrs + (list (car (bbdb-record-finger-host (car record))))))) + ((stringp which-address) + (setq addrs (nconc addrs (list which-address)))) + ((numberp which-address) + (setq addrs + (nconc addrs + (list (nth which-address + (bbdb-record-finger-host (car record))))))) + (t + (setq addrs + (nconc addrs + (copy-sequence (bbdb-record-finger-host + (car record))))))) + (setq record (cdr record))) + (if (car addrs) + (save-excursion + (with-output-to-temp-buffer bbdb-finger-buffer-name + (set-buffer bbdb-finger-buffer-name) + (make-local-variable 'bbdb-remaining-addrs-to-finger) + (setq bbdb-remaining-addrs-to-finger (cdr addrs)) + (bbdb-finger-internal (car addrs)))) + (error "Nothing to finger!")))) + + +(defun bbdb-remove-duplicate-nets (records) + "*Remove duplicate nets from a record." + (interactive (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (bbdb-current-record))) + (let (nets cnets) + (while records + (setq nets (bbdb-record-net (car records)) + cnets nil) + (while nets + (add-to-list 'cnets (car nets)) + (setq nets (cdr nets))) + (bbdb-record-set-net (car records) cnets) + (setq records (cdr records))))) + +(defun bbdb-find-duplicates (&optional fields) + "Find all records that have duplicate entries for given FIELDS. +FIELDS should be a list of the symbols `name', `net', and/or `aka'. +Note that overlap between these fields is noted if either is selected, +most common case `aka' and `name'. If FIELDS is not given it +defaults to all of them. + +The results of the search is returned as a list of records." + (setq fields (or fields '(name net aka))) + (let ((records (bbdb-records)) + rec hash ret) + (while records + (setq rec (car records)) + + (when (and (memq 'name fields) + (bbdb-record-name rec) + (setq hash (bbdb-gethash (downcase (bbdb-record-name rec)))) + (> (length hash) 1)) + (setq ret (append hash ret)) + (message "BBDB record `%s' causes duplicates, maybe it is equal to a company name." + (bbdb-record-name rec)) + (sit-for 0)) + + (if (memq 'net fields) + (let ((nets (bbdb-record-net rec))) + (while nets + (setq hash (bbdb-gethash (downcase (car nets)))) + (when (> (length hash) 1) + (setq ret (append hash ret)) + (message "BBDB record `%s' has duplicate net `%s'." + (bbdb-record-name rec) (car nets)) + (sit-for 0)) + (setq nets (cdr nets))))) + + (if (memq 'aka fields) + (let ((aka (bbdb-record-aka rec))) + (while aka + (setq hash (bbdb-gethash (downcase (car aka)))) + (when (> (length hash) 1) + (setq ret (append hash ret)) + (message "BBDB record `%s' has duplicate aka `%s'" + (bbdb-record-name rec) (car aka)) + (sit-for 0)) + (setq aka (cdr aka))))) + + (setq records (cdr records))) + (reverse (bbdb-remove-memq-duplicates ret)))) + +(defun bbdb-show-duplicates (&optional fields) + "*Find all records that have duplicate entries for given FIELDS. +FIELDS should be a list of the symbols `name', `net', and/or `aka'. +Note that overlap between these fields is noted if either is selected +(most common case `aka' and `name'). If FIELDS is not given it +defaults to all of them. + +The results are displayed in the bbdb buffer." + (interactive) + (setq fields (or fields '(name net aka))) + (bbdb-display-records (bbdb-find-duplicates fields))) + +;;; Time-based functions +(defun bbdb-kill-older (date &optional compare function) + "*Apply FUNCTION to all records with timestamps older than DATE. +The comparison is done with COMPARE. If FUNCTION is not specified, the +selected records are deleted. If COMPARE is not specified, +`string-lessp' is used. + +Example: + (bbdb-kill-older \"1997-01-01\") +will delete all records with timestamps older than Jan 1 1997. + +Notes: 1. Records without timestamp fields will be ignored +2. DATE must be in yyyy-mm-dd format." + (interactive "sKill records with timestamp older than (yyyy-mm-dd): \n") + (let ((records (bbdb-records)) timestamp + (fun (or function 'bbdb-delete-record-internal)) + (cmp (or compare 'string-lessp))) + (while records + (if (and (setq timestamp (bbdb-record-getprop (car records) 'timestamp)) + (funcall cmp timestamp date)) + (funcall fun (car records))) + (setq records (cdr records))))) + +(defmacro bbdb-compare-records (cmpval field compare) + "Builds a lambda comparison function that takes one argument, REC. +REC is returned if +(COMPARE VALUE CMPVAL) +is true, where VALUE is the value of the FIELD field of REC." + `(lambda (rec) +(let ((val (bbdb-record-getprop rec ,field))) + (if (and val (,compare val ,cmpval)) + rec nil)))) + +;;;###autoload +(defun bbdb-timestamp-older (date) + "*Display records with timestamp older than DATE. +DATE must be in yyyy-mm-dd format." + (interactive "sOlder than date (yyyy-mm-dd): ") + (bbdb-display-some (bbdb-compare-records date 'timestamp string<))) + +;;;###autoload +(defun bbdb-timestamp-newer (date) + "*Display records with timestamp newer than DATE. +DATE must be in yyyy-mm-dd format." + (interactive "sNewer than date (yyyy-mm-dd): ") + (bbdb-display-some (bbdb-compare-records date 'timestamp string>))) + +;;;###autoload +(defun bbdb-creation-older (date) + "*Display records with creation-date older than DATE. +DATE must be in yyyy-mm-dd format." + (interactive "sOlder than date (yyyy-mm-dd): ") + (bbdb-display-some (bbdb-compare-records date 'creation-date string<))) + +;;;###autoload +(defun bbdb-creation-newer (date) + "*Display records with creation-date newer than DATE. +DATE must be in yyyy-mm-dd format." + (interactive "sNewer than date (yyyy-mm-dd): ") + (bbdb-display-some (bbdb-compare-records date 'creation-date string>))) + +;;;###autoload +(defun bbdb-creation-no-change () + "*Display records that have the same timestamp and creation-date." + (interactive) + (bbdb-display-some + (bbdb-compare-records (bbdb-record-getprop rec 'timestamp) + 'creation-date string=))) + +;;; Help and documentation + +(defcustom bbdb-info-file nil + "*Set this to the location of the bbdb info file, if it's not in the +standard place." + :group 'bbdb + :type '(choice (const :tag "Standard location" nil) + (file :tag "New location"))) + +;;;###autoload +(defun bbdb-info () + (interactive) + (require 'info) + (if bbdb-inside-electric-display + (bbdb-electric-throw-to-execute '(bbdb-info)) + (let ((file (or bbdb-info-file "bbdb"))) + (Info-goto-node (format "(%s)Top" file))))) + +;;;###autoload +(defun bbdb-help () + (interactive) + (message (substitute-command-keys "\\\ +new field: \\[bbdb-insert-new-field]; \ +edit field: \\[bbdb-edit-current-field]; \ +delete field: \\[bbdb-delete-current-field-or-record]; \ +mode help: \\[describe-mode]; \ +info: \\[bbdb-info]"))) + + +(or (fboundp 'member);; v18 lossage + (defun member (item list) + (while (and list (not (equal item (car list)))) (setq list (cdr list))) + list)) + + +;;; If Sebastian Kremer's minibuffer history package is around, use it. +(if (and (fboundp 'gmhist-make-magic) + (string-lessp emacs-version "19")) ; v19 has history built in + (mapcar 'gmhist-make-magic + '(bbdb bbdb-name bbdb-company bbdb-net bbdb-changed))) + +;;;###autoload +(defcustom bbdb-update-records-mode 'annotating + "Controls how `bbdb-update-records' processes email addresses. +Set this to an expression which evaluates either to 'searching or +'annotating. When set to 'annotating email addresses will be fed to +`bbdb-annotate-message-sender' in order to update existing records or create +new ones. A value of 'searching will search just for existing records having +the right net. + +There is a version of this variable for each MUA, which overrides this variable +when set! + +This variable is also used for inter-function communication between the +functions `bbdb-update-records' and `bbdb-prompt-for-create'." + :group 'bbdb-mua-specific + :type '(choice (const :tag "annotating all messages" + annotating) + (const :tag "annotating no messages" + searching) + (sexp :tag "user defined"))) + +(defvar bbdb-offer-to-create nil + "Used for inter-function communication between the functions +`bbdb-update-records' and `bbdb-prompt-for-create'.") +(defvar bbdb-address nil + "Used for inter-function communication between the functions +`bbdb-update-records' and `bbdb-prompt-for-create'.") + +(defvar bbdb-update-address-class nil + "Class of currently processed address as in `bbdb-get-addresses-headers'. +The `bbdb-notice-hook' and `bbdb-create-hook' functions may utilize this to +treat updates in the right way.") + +(defvar bbdb-update-address-header nil + "Header the currently processed address was extracted from. +The `bbdb-notice-hook' and `bbdb-create-hook' functions may utilize this to +treat updates in the right way.") + +;;;###autoload +(defun bbdb-update-records (addrs auto-create-p offer-to-create) + "Returns the records corresponding to the list of addresses ADDRS, +creating or modifying them as necessary. A record will be created if +AUTO-CREATE-P is non-nil or if OFFER-TO-CREATE is true and the user +confirms the creation. + +The variable `bbdb/gnus-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked any more for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." + (setq auto-create-p (bbdb-invoke-hook-for-value auto-create-p)) + + (let ((bbdb-records (bbdb-records)) + (processed-addresses 0) + (bbdb-offer-to-create (or offer-to-create (eq 'prompt auto-create-p))) + (bbdb-update-records-mode + (if offer-to-create 'annotating + (if (listp bbdb-update-records-mode) + (eval bbdb-update-records-mode) + bbdb-update-records-mode))) + (addrslen (length addrs)) + (bbdb-update-address-class nil) + (bbdb-update-address-header nil) + records hits) + + (while addrs + + (setq bbdb-address (car addrs) + bbdb-update-address-class (car bbdb-address) + bbdb-update-address-header (cadr bbdb-address) + bbdb-address (caddr bbdb-address)) + + (condition-case nil + (progn + (setq hits + (cond ((null (cadr bbdb-address)) + ;; ignore emtpy addrs, e.g. (??? nil) + nil) + ((eq bbdb-update-records-mode 'annotating) + (list;; search might return a list + (bbdb-annotate-message-sender + bbdb-address t + (or offer-to-create;; force create + auto-create-p) + 'bbdb-prompt-for-create))) + ((eq bbdb-update-records-mode 'searching) + ;; search for records having this net + (let ((net (concat "^" + (regexp-quote + (cadr bbdb-address)) + "$")) + ;; there is no case for nets + (bbdb-case-fold-search t)) + (bbdb-search bbdb-records nil nil net)))) + processed-addresses (+ processed-addresses 1)) + + (when (and (not bbdb-silent-running) + (not bbdb-gag-messages) + (not (eq bbdb-offer-to-create 'quit)) + (= 0 (% processed-addresses 5))) + (let ((mess (format "Hit C-g to stop BBDB from %s. %d of %d addresses processed." + bbdb-update-records-mode processed-addresses addrslen))) + (if (featurep 'xemacs) + (bbdb-display-message 'progress mess) + (message mess))) + (sit-for 0))) + + ;; o.k. there was a quit signal so how should we proceed now? + (quit (cond ((eq bbdb-update-records-mode 'annotating) + (setq bbdb-update-records-mode 'searching)) + ((eq bbdb-update-records-mode 'searching) + nil) + ((eq bbdb-update-records-mode 'next) + (setq bbdb-update-records-mode 'annotating)) + (t + (setq bbdb-update-records-mode 'quit))) + nil)) + + (while hits + ;; people should be listed only once so we use add-to-list + (if (car hits) (add-to-list 'records (car hits))) + (setq hits (cdr hits))) + + (setq addrs (cdr addrs))) + + ;; add-to-list adds at the front so we have to reverse the list in order + ;; to reflect the order of the records as they appear in the headers. + (setq records (nreverse records)) + + records)) + +(defun bbdb-get-help-window (message) + "Display MESSAGE in a new window which is the last one in the current frame." + (let ((b (get-buffer-create " *BBDB Help*")) + (w (or (get-buffer-window " *BBDB Help*") + (get-lru-window))) + (lines (let ((l 2) (s 0)) + (while (setq s (string-match "\n" message s)) + (setq s (1+ s) l (1+ l))) + l))) + + (setq w (split-window w)) + (select-window w) + (switch-to-buffer b) + (erase-buffer) + (insert message) + (goto-char (point-min)) + (let ((window-min-height 1)) + (enlarge-window (- lines (window-height w)))) + w)) + +(defun bbdb-kill-help-window (window) + "Kill the buffer corresponding to WINDOW and delete the WINDOW." + (kill-buffer (window-buffer window)) + (delete-window window)) + +;; This is a hack. The function is called by bbdb-annotate-message-sender and +;; uses the above variable in order to manipulate bbdb-update-records. +;; Some cases are handled with signals in order to keep the changes in +;; bbdb-annotate-message-sender as minimal as possible. + +(defun bbdb-prompt-for-create () + "This function is used by `bbdb-update-records' to ask the user how to +proceed the processing of records. + +It is called from `bbdb-annotate-message-sender' (PROMPT-FOR-CREATE arg) and +returns `t' if the record should be created or `nil' otherwise. It honors a +previous answer, e.g. \"!\" add all ..." + (let ((old-offer-to-create bbdb-offer-to-create) + event prompt) + (when bbdb-offer-to-create + (when (not (integerp bbdb-offer-to-create)) + (setq prompt (format "%s is not in the db; add? (y,!,n,s,q,?) " + (or (car bbdb-address) (cadr bbdb-address)))) + (while (not event) + (setq event (read-key-sequence prompt)) + (if (featurep 'xemacs) + (setq event (bbdb-event-to-character (aref event 0))) + (setq event (if (stringp event) (aref event 0))))) + + (setq bbdb-offer-to-create event)) + (message "");; clear the message buffer + + (cond ((eq bbdb-offer-to-create ?y) + (setq bbdb-offer-to-create old-offer-to-create) + t) + ((eq bbdb-offer-to-create ?!) + t) + ((or (eq bbdb-offer-to-create ?n) + (eq bbdb-offer-to-create ? )) + (setq bbdb-update-records-mode 'next + bbdb-offer-to-create old-offer-to-create) + (signal 'quit nil)) + ((eq bbdb-offer-to-create ?q) + (setq bbdb-update-records-mode 'quit) + (signal 'quit nil)) + ((eq bbdb-offer-to-create ?s) + (setq bbdb-update-records-mode 'searching) + (signal 'quit nil)) + (t + (let ((w (bbdb-get-help-window + "Your answer controls how BBDB updates/searches for records. + +Type ? for this help. +Type y to add the current record. +Type ! to add all remaining records. +Type n to skip the current record. (You might also type space) +Type s to switch from annotate to search mode. +Type q to quit updating records. No more search or annotation is done."))) + (setq bbdb-offer-to-create nil) + (condition-case error + (progn (bbdb-prompt-for-create) + (bbdb-kill-help-window w)) + (t + (bbdb-kill-help-window w) + (apply 'signal error))))))))) + +;;;###autoload +(defcustom bbdb-get-addresses-headers + '((authors . ("From" "Resent-From" "Reply-To")) + (recipients . ("Resent-To" "Resent-CC" "To" "CC" "BCC"))) + "*List of headers to search for senders and recipients email addresses. +The headers are grouped into two classes, the authors and the senders headers." + :group 'bbdb-mua-specific + :type 'list) + +;;;###autoload +(defcustom bbdb-get-only-first-address-p + t + "*If t `bbdb-update-records' will return only the first one. +Changing this variable will show its effect only after clearing the +`bbdb-message-cache' of a folder or closing and visiting it again." + :group 'bbdb-mua-specific + :type 'boolean) + +(defun bbdb-get-addresses (only-first-address + uninteresting-senders + get-header-content-function + &rest get-header-content-function-args) + "" + (let ((headers bbdb-get-addresses-headers) + (ignore-senders (or bbdb-user-mail-names uninteresting-senders)) + addrlist adlist fn ad + header-type header-fields header-content) + (while headers + (setq header-type (caar headers) + header-fields (cdar headers)) + (while header-fields + (setq header-content (apply get-header-content-function + (car header-fields) + get-header-content-function-args)) + (when header-content + (setq adlist (funcall bbdb-extract-address-components-func + header-content)) + (while adlist + (setq fn (caar adlist) + ad (car (cdar adlist))) + + ;; ignore uninteresting addresses, this is kinda gross! + (if (or (not (stringp ignore-senders)) + (not (or (and fn (string-match ignore-senders fn)) + (and ad (string-match ignore-senders ad))))) + (add-to-list 'addrlist + (list header-type + (car header-fields) + (car adlist)))) + + (if (and only-first-address addrlist) + (setq adlist nil headers nil) + (setq adlist (cdr adlist))))) + (setq header-fields (cdr header-fields))) + (setq headers (cdr headers))) + (nreverse addrlist))) + +(provide 'bbdb-com) diff --git a/xemacs-packages/lisp/bbdb/bbdb-com.elc b/xemacs-packages/lisp/bbdb/bbdb-com.elc new file mode 100644 index 0000000000000000000000000000000000000000..8bf5145632369f0f18fc0aab7665aa557a052ae4 GIT binary patch literal 94423 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. +;;; +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;; This file was written by Ivan Vazquez + +;;; $Id: bbdb-ftp.el,v 1.8 2005/07/24 15:22:57 waider Exp $ + +;;; This file adds the ability to define ftp-sites in a BBDB, much the same +;;; way one adds a regular person's name to the BBDB. It also defines the +;;; bbdb-ftp command which allows you to ftp a site that is in a bbdb-record. +;;; You must have either EFS or ange-ftp in order to use this code. Ange-ftp +;;; is available at archive.cis.ohio-state.edu in the +;;; /pub/gnu/emacs/elisp-archive/packages directory. EFS ships with XEmacs. + +;;; Note that Ftp Site BBDB entries differ from regular entries by the +;;; fact that the Name Field must have the ftp site preceeded by the +;;; bbdb-ftp-site-name-designator-prefix. This defaults to "Ftp Site:" +;;; BBDB Ftp Site entries also have two new fields added, the +;;; ftp-dir slot, and the ftp-user slot. These are added to the notes +;;; alist part of the bbdb-records, the original bbdb-record structure +;;; remains untouched. + +;;; The following user-level commands are defined for use: +;;; + +;;; bbdb-ftp - Use ange-ftp to open an ftp-connection to a BBDB +;;; record's name. If this command is executed from the +;;; *BBDB* buffer, ftp the site of the record at point; +;;; otherwise, it prompts for an ftp-site. + +;;; bbdb-create-ftp-site - +;;; Add a new ftp-site entry to the bbdb database; prompts +;;; for all relevant info using the echo area, inserts the +;;; new record in the db, sorted alphabetically. + +;;; The package can be installed by compiling and adding the following +;;; two lines to your .emacs. + +;;; (autoload 'bbdb-ftp "bbdb-ftp" "Ftp BBDB Package" t) +;;; (autoload 'bbdb-create-ftp-site "bbdb-ftp" "Ftp BBDB Package" t) + +(require 'bbdb) + +;; There must be a better way +(if (featurep 'efs-cu) + (require 'efs) + (require 'ange-ftp)) + +(defcustom bbdb-default-ftp-user "anonymous" + "*The default login to use when ftp-ing." + :group 'bbdb-utilities-ftp + :type 'string) + +(defcustom bbdb-default-ftp-dir "/" + "*The default directory to open when ftp-ing." + :group 'bbdb-utilities-ftp + :type 'string) + +(defcustom bbdb-ftp-site-name-designator-prefix "Ftp Site: " + "*The prefix that all ftp sites in the bbdb will have in their name field." + :group 'bbdb-utilities-ftp + :type 'string) + +(defmacro defun-bbdb-raw-notes-accessor (slot) + "Expands into an accessor function for slots in the notes alist." + (let ((fn-name (intern (concat "bbdb-record-" (symbol-name slot))))) + (list 'defun fn-name (list 'record) + (list 'cdr + (list 'assoc (list 'quote slot) + (list 'bbdb-record-raw-notes 'record)))))) + +(defun-bbdb-raw-notes-accessor ftp-dir) +(defun-bbdb-raw-notes-accessor ftp-user) + +(defun bbdb-record-ftp-site (record) + "Accessor Function. Returns the ftp-site field of the BBDB record or nil." + (let* ((name (bbdb-record-name record)) + (ftp-pfx-regexp (concat bbdb-ftp-site-name-designator-prefix " *")) + (ftp-site + (and (string-match ftp-pfx-regexp name) + (substring name (match-end 0))))) + ftp-site)) + +(defun remove-leading-whitespace (string) + "Remove any spaces or tabs from only the start of the string." + (let ((space-char-code (string-to-char " ")) + (tab-char-code ?\t) + (index 0)) + (if string + (progn + (while (or (char-equal (elt string index) space-char-code) + (char-equal (elt string index) tab-char-code)) + (setq index (+ index 1))) + (substring string index)) + nil))) + +;;;###autoload +(defun bbdb-ftp (bbdb-record &optional which) + "Use ange-ftp to open an ftp-connection to a BBDB record's name. +If this command is executed from the *BBDB* buffer, ftp the site of +the record at point; otherwise, it prompts for an ftp-site." + (interactive (list (bbdb-get-record "Visit (FTP): ") + (or current-prefix-arg 0))) + (if (bbdb-record-ftp-site bbdb-record) + (bbdb-ftp-internal bbdb-record) + (find-file-other-window + (read-string "fetch: " (bbdb-get-field bbdb-record 'ftp which))))) + +(defun bbdb-ftp-internal (bbdb-record) + (let* ((site (bbdb-record-ftp-site bbdb-record)) + (dir (or (bbdb-record-ftp-dir bbdb-record) bbdb-default-ftp-dir)) + (user (or (bbdb-record-ftp-user bbdb-record) bbdb-default-ftp-user)) + (file-string (concat "/" user "@" site ":" dir ))) + (if bbdb-inside-electric-display + (bbdb-electric-throw-to-execute (list 'bbdb-ftp-internal bbdb-record))) + (if site + (find-file-other-window file-string) + (error "Not an ftp site. Check bbdb-ftp-site-name-designator-prefix")))) + +(defun bbdb-read-new-ftp-site-record () + "Prompt for and return a completely new BBDB record that is +specifically an ftp site entry. Doesn't insert it in to the database +or update the hashtables, but does insure that there will not be name +collisions." + (bbdb-records) ; make sure database is loaded + (if bbdb-readonly-p (error "The Insidious Big Brother Database is read-only.")) + (let (site dir user) + (bbdb-error-retry + (progn + (setq site (bbdb-read-string "Ftp Site: ")) + ;; try and parse it out, in case the user typed in things like + ;; "ftp://user@site/directory/ or /user@site/directory + (if (string-match + "^\\([Ff][Tt][Pp]://\\|/\\)?\\([^@/]@\\)?\\([^/]+\\)\\(/[^/].*\\)?" + site) + (setq user (if (match-beginning 2) + (substring site (match-beginning 2) + (match-end 2))) + dir (if (match-beginning 4) + (substring site (match-beginning 4) + (match-end 4))) + site (substring site (match-beginning 3) + (match-end 3))) + (if (string-match "/" site) + (error "%s doesn't look like a valid site name." site))) + (setq site (concat bbdb-ftp-site-name-designator-prefix site)) + (if (and bbdb-no-duplicates-p + (bbdb-gethash (downcase site))) + (error "%s is already in the database" site)))) + (let* ((dir (or dir (bbdb-read-string "Ftp Directory: " + bbdb-default-ftp-dir))) + (user (or user (bbdb-read-string "Ftp Username: " + bbdb-default-ftp-user))) + (company (bbdb-read-string "Company: ")) + (notes (bbdb-read-string "Additional Comments: ")) + (names (bbdb-divide-name site)) + (firstname (car names)) + (lastname (nth 1 names))) + (if (string= user bbdb-default-ftp-user) (setq user nil)) + (if (string= company "") (setq company nil)) + (if (or (string= dir bbdb-default-ftp-dir) (string= dir "")) + (setq dir nil)) + (if (string= notes "") (setq notes nil)) + + (let ((record + (vector firstname lastname nil company nil nil nil + (append + (if notes (list (cons 'notes notes)) nil) + (if dir (list (cons 'ftp-dir dir)) nil) + (if user (list (cons 'ftp-user user)) nil)) + (make-vector bbdb-cache-length nil)))) + record)))) + +;;;###autoload +(defun bbdb-create-ftp-site (record) + "Add a new ftp-site entry to the bbdb database. +Prompts for all relevant info using the echo area, +inserts the new record in the db, sorted alphabetically." + (interactive (list (bbdb-read-new-ftp-site-record))) + (bbdb-invoke-hook 'bbdb-create-hook record) + (bbdb-change-record record t) + (bbdb-display-records (list record))) + +(provide 'bbdb-ftp) diff --git a/xemacs-packages/lisp/bbdb/bbdb-ftp.elc b/xemacs-packages/lisp/bbdb/bbdb-ftp.elc new file mode 100644 index 0000000000000000000000000000000000000000..fa106fe3a01d15b7318a21a192d1b4f5e544ce96 GIT binary patch literal 4986 zcmcIoZEq9V73NdrI5<)lkVpdbc+zg{kg;P20)!76k`Q%QtAe_0TPZf`c;?z3Wjr&? zjPp|UOSgeFT~+-8>Q<^$^()z+{sfl1LwMQu{+vGN-m!5~sCGXTiOkHMd(S=hInQ~{ z8DGBo{>5BhGB-f zZmaHLr|krrXbh6lw$?i^)&BQon$xR537y=J50(FgUw zZulDg<|><|_nW3|<>d0pN+kGbuPo$>7vg!B+4(Vj?2=w6s@a|&*$w-5M#OvBAE5X`=)2%x>UE}hvkv$MI@H(Fe2L};PPXTeIQWb;{4Wzmf$i3GM}(nI2h5UI9MiJdY*Nk>L4Yl^-!jB8 zu*0-ugs&oA#e3znTnD$=r?$stGYEtm>5gYuIzkj>vA2kB(SN-l*LJWg)-&olV?^4c z&(p2P8|k$>k2ce-2dj^^(yd1yYcwB-TTMF<#BNbl7*R72I7czGwutQ32P6<*_VLHJVPu({-jC4Qqz$xhoB?8ET}B+^7qR=aA#o z5TwW>Ohg2QOS}qD<}{kD1zrk0fK$e8$;PX?u_)qEoRs%KstCvWL3j>LO`NBz%RZ8Yw*VxDONMEJ-5_JN>6$Vp znW~}VMIASgdGN_#Ugmz1%y5t$8{{6wUDMTNAOmAbm-F>VE>~tF?1QzmfFouVZEiH8Wh=2_ywyqCsm)zcxwtl;J=l<@s5k^5SZSVRf z;>Q8vX?}GXF{z1VUop6QYe{L1Mi67AxeZx=#@J!t+K$^qp@_I8!Q>*&-tdqWhPy%` ziX7LBfFh%UD#B&ba~-5TvM7v<0HsyIp{yT-AdrTj@`lA~kBS4nvqec<=?>z*xs~4D z8SFn+{@CDL%L>q)r*mRn-E zed5TI6IdSTol-<&Bv(Vj4M)K+-iG1g#c>5g;nFyL2#swEc}M4v*$lbqxh@otOD(56 zb+KVMlu^hf-(_S_dr`t0Tt{&$mWA1j(1}PS8N?A@IYO0YwJL&9DOD0%=9^bd@_ig> zh?(ypeJ_)T(O}6A#VFYrL{NN)3d>9E9dqqqDB6@_9y63 zp7h6?TiZK5yNRKamS)^lztFw5>s}Tw$?*0@C`v3eFkD42bnZWN>9@XwXKx9oLP?Ip zrBwx*A{KDDye3c$S%n#nGF^zHQ!JcA*OXzoM1|*$fG5W2Xuqta2J=4`hGmHS8|^mecJo4ANBXW zwRUI!S!y=jI=XiIc~APmA78vok9N|SMZI0!S@|Ro@v)^4@!%`u;?uktS~Wr9%_|R2 zlqO}po&wz`V?c!it_HTLNA>9D%j`-OV`aq@3zq=rB6J0nnIEJ$Ns(bJE{G9`}eOMf5x}Z?mfGI?O5vhz32C@op|uc zlNUVe_RBADX_eg6^%Fho|NJub*WfF<)k>_lzW(OhzW#JNeP-ZK-+gknq`kMk`tskH zThh7^sx)gVPh3y8n!W=%q8{r0_evh(Y?ly9Xk{Y5{`@h#UFtg5)gdeC(N!0q-7J+d z^K;em{EetQf88%n=JTb}@9{tT4!^lMl`l_q9`fb0xW{;Y{${?M8{rok712bD6H87U z%AbWY6*!w5&s!kJUO*kCMfA3oQabKQ5J4rldgxV=94zOm2okHhx^35r_(}FMuijFo zJJdaEt0-Nqjm<5DDA9qvlclsop;VWSQQlI?DJnMD6qRW_3%SPuz%|2RwynU+10oQM znEakzLgR}~$6oU{8 zpRSCuUkJF)#l0x~%kp1^mrRFt3FRQqwm-|{w-Aqf2svZeg=e0=B0k}O+zE*g@L4Pyb{v}%r8-c|DC3^v3+K?GqW zZ8}DL)1fNobUP7D!>kK5jczTfm#NThQOC#5^QQ$`)WZ1*g8SeU%RT!cQ$k8PcVn#C zY`G)cxuhx`agPK&4#0#(!)2AP^2fBqAImr-#330?s!E`~0C=CcGPmha86|{~TRFq= z>qbRHs=B;J(@oezQS3O{{SknVA8=$Nv5CK1i5b~xb@u?ayXXPlIwz7uD>l|OP?tSw nyyy^#VtRuzaSwHFV(d^4B}w#}ilh1@G?&bU_*VrSA)EXU|DnD8 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-gnus.el b/xemacs-packages/lisp/bbdb/bbdb-gnus.el new file mode 100644 index 00000000..193f8e9a --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-gnus.el @@ -0,0 +1,814 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file is part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992, 1993 Jamie Zawinski . +;;; Interface to GNUS version 3.12 or greater. See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-gnus.el,v 1.8 2005/07/24 15:22:57 waider Exp $ +;; + +(require 'bbdb) +(require 'bbdb-snarf) +(require 'gnus) + +(eval-and-compile + (require 'bbdb-com) + (require 'rfc822)) + +;; Cater for older emacs (19.34) with default Gnus installation. +(eval-and-compile + (condition-case nil + (progn + (require 'gnus-win) + (require 'gnus-sum) + (require 'gnus-art)) + (error nil))) + +;;; Compiler hushing +(eval-when-compile + (defvar gnus-optional-headers)) + +(defun bbdb/gnus-get-message-id () + "Return the message-id of the current message." + (save-excursion + (set-buffer gnus-original-article-buffer) + (goto-char (point-min)) + (let ((case-fold-search t)) + (if (re-search-forward "^Message-ID:\\s-*\\(<.+>\\)" (point-max) t) + (match-string 1))))) + +(defcustom bbdb/gnus-update-records-mode 'annotating +; '(if (gnus-new-flag msg) 'annotating 'searching) + "Controls how `bbdb/gnus-update-records' processes email addresses. +Set this to an expression which evaluates either to 'searching or +'annotating. When set to 'annotating email addresses will be fed to +`bbdb-annotate-message-sender' in order to update existing records or create +new ones. A value of 'searching will search just for existing records having +the right net. + +The default is to annotate only new messages." + :group 'bbdb-mua-specific-gnus + :type '(choice (const :tag "annotating all messages" + annotating) + (const :tag "annotating no messages" + searching) + (const :tag "annotating only new messages" + (if (equal "" + (gnus-summary-article-mark + (gnus-summary-article-number))) + 'annotating 'searching)) + (sexp :tag "user defined"))) + + +;;;###autoload +(defun bbdb/gnus-update-record (&optional offer-to-create) + "Return the record corresponding to the current GNUS message, creating +or modifying it as necessary. A record will be created if +bbdb/news-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." + (let* ((bbdb-get-only-first-address-p t) + (records (bbdb/gnus-update-records offer-to-create))) + (if records (car records) nil))) + +;;;###autoload +(defun bbdb/gnus-update-records (&optional offer-to-create) + "Return the records corresponding to the current GNUS message, creating +or modifying it as necessary. A record will be created if +bbdb/news-auto-create-p is non-nil or if OFFER-TO-CREATE is true +and the user confirms the creation. + +The variable `bbdb/gnus-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked anymore for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." + (let ((bbdb-update-records-mode (or bbdb/gnus-update-records-mode + bbdb-update-records-mode)) + (bbdb/gnus-offer-to-create offer-to-create) + ;; here we may distiguish between different type of messages + ;; for those that have no message id we have to find something + ;; else as message key. + (msg-id (bbdb/gnus-get-message-id)) + records cache) + (save-excursion + (set-buffer gnus-article-buffer) + + (if (and msg-id (not bbdb/gnus-offer-to-create)) + (setq cache (bbdb-message-cache-lookup msg-id))) + + (if cache + (setq records (if bbdb-get-only-first-address-p + (list (car cache)) + cache)) + + (let ((bbdb-update-records-mode (or bbdb/gnus-update-records-mode + bbdb-update-records-mode))) + (setq records (bbdb-update-records + (bbdb-get-addresses + bbdb-get-only-first-address-p + (or (if (boundp 'gnus-ignored-from-addresses) + gnus-ignored-from-addresses) + bbdb-user-mail-names) + 'gnus-fetch-field) + bbdb/news-auto-create-p + offer-to-create))) + (if (and bbdb-message-caching-enabled msg-id) + (bbdb-encache-message msg-id records)))) + records)) + +;;;###autoload +(defun bbdb/gnus-annotate-sender (string &optional replace) + "Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." + (interactive (list (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.") + (read-string "Comments: ")))) + (gnus-summary-select-article) + (bbdb-annotate-notes (bbdb/gnus-update-record t) string 'notes replace)) + +(defun bbdb/gnus-edit-notes (&optional arg) + "Edit the notes field or (with a prefix arg) a user-defined field +of the BBDB record corresponding to the sender of this message." + (interactive "P") + (gnus-summary-select-article) + (let ((record (or (bbdb/gnus-update-record t) (error "unperson")))) + (bbdb-display-records (list record)) + (if arg + (bbdb-record-edit-property record nil t) + (bbdb-record-edit-notes record t)))) + +;;;###autoload +(defun bbdb/gnus-show-records (&optional address-class) + "Display the contents of the BBDB for all addresses of this message. +This buffer will be in `bbdb-mode', with associated keybindings." + (interactive) + (gnus-summary-select-article) + (let ((bbdb-get-addresses-headers + (if address-class + (list (assoc address-class bbdb-get-addresses-headers)) + bbdb-get-addresses-headers)) + (bbdb/gnus-update-records-mode 'annotating) + (bbdb-message-cache nil) + (bbdb-user-mail-names nil) + (gnus-ignored-from-addresses nil) + records) + (setq records (bbdb/gnus-update-records t)) + (if records + (bbdb-display-records records) + (bbdb-undisplay-records)) + records)) + +;;;###autoload +(defun bbdb/gnus-show-all-recipients () + "Show all recipients of this message. Counterpart to `bbdb/vm-show-sender'." + (interactive) + (let ((bbdb-get-only-first-address-p nil)) + (bbdb/gnus-show-records 'recipients))) + +(defun bbdb/gnus-show-sender (&optional show-recipients) + "Display the contents of the BBDB for the senders of this message. +With a prefix argument show the recipients instead, +with two prefix arguments show all records. +This buffer will be in `bbdb-mode', with associated keybindings." + (interactive "p") + (cond ((= 4 show-recipients) + (bbdb/gnus-show-all-recipients)) + ((= 16 show-recipients) + (let ((bbdb-get-only-first-address-p nil)) + (bbdb/gnus-show-records))) + (t + (if (null (bbdb/gnus-show-records 'authors)) + (bbdb/gnus-show-all-recipients))))) + +(defun bbdb/gnus-pop-up-bbdb-buffer (&optional offer-to-create) + "Make the *BBDB* buffer be displayed along with the GNUS windows, +displaying the record corresponding to the sender of the current message." + (let ((bbdb-gag-messages t) + (records (bbdb/gnus-update-records offer-to-create)) + (bbdb-electric-p nil)) + + (when bbdb-use-pop-up + (let ((b (current-buffer))) + ;; display the bbdb buffer iff there is a record for this article. + (if records + (bbdb-pop-up-bbdb-buffer + (lambda (w) + (let ((b (current-buffer))) + (set-buffer (window-buffer w)) + (prog1 (eq major-mode 'gnus-article-mode) + (set-buffer b))))) + (or bbdb-inside-electric-display + (not (get-buffer-window bbdb-buffer-name)) + (let (w) + (delete-other-windows) + (gnus-configure-windows 'article) + (if (setq w (get-buffer-window gnus-summary-buffer)) + (select-window w))))) + (set-buffer b)) + (if records (bbdb-display-records records bbdb-pop-up-display-layout))) + records)) + +;; +;; Announcing BBDB entries in the summary buffer +;; + +(defcustom bbdb/gnus-lines-and-from-length 18 + "*The number of characters used to display From: info in Gnus, if you have +set gnus-optional-headers to 'bbdb/gnus-lines-and-from." + :group 'bbdb-mua-specific-gnus + :type 'integer) + +(defcustom bbdb/gnus-summary-mark-known-posters t + "*If t, mark messages created by people with records in the BBDB. +In GNUS, this marking will take place in the subject list (assuming +`gnus-optional-headers' contains `bbdb/gnus-lines-and-from'). In Gnus, the +marking will take place in the Summary buffer if the format code defined by +`bbdb/gnus-summary-user-format-letter' is used in `gnus-summary-line-format'. +This variable has no effect on the marking controlled by +`bbdb/gnus-summary-in-bbdb-format-letter'." + :group 'bbdb-mua-specific-gnus + :type '(choice (const :tag "Mark known posters" t) + (const :tag "Do not mark known posters" nil))) +(defvaralias 'bbdb/gnus-mark-known-posters + 'bbdb/gnus-summary-mark-known-posters) + +(defcustom bbdb/gnus-summary-known-poster-mark "+" + "This is the default character to prefix author names with if +bbdb/gnus-summary-mark-known-posters is t. If the poster's record has +an entry in the field named by bbdb-message-marker-field, then that will +be used instead." + :group 'bbdb-mua-specific-gnus + :type 'character) + +(defcustom bbdb/gnus-summary-show-bbdb-names t + "*If both this variable and `bbdb/gnus-summary-prefer-real-names' are true, +then for messages from authors who are in your database, the name +displayed will be the primary name in the database, rather than the +one in the From line of the message. This doesn't affect the names of +people who aren't in the database, of course. (`gnus-optional-headers' +must be `bbdb/gnus-lines-and-from' for GNUS users.)" + :group 'bbdb-mua-specific-gnus + :type 'boolean) +(defvaralias 'bbdb/gnus-header-show-bbdb-names + 'bbdb/gnus-summary-show-bbdb-names) + +(defcustom bbdb/gnus-summary-prefer-bbdb-data t + "If t, then for posters who are in our BBDB, replace the information +provided in the From header with data from the BBDB." + :group 'bbdb-mua-specific-gnus + :type 'boolean) + +(defcustom bbdb/gnus-summary-prefer-real-names t + "If t, then display the poster's name from the BBDB if we have one, +otherwise display his/her primary net address if we have one. If it +is set to the symbol bbdb, then real names will be used from the BBDB +if present, otherwise the net address in the post will be used. If +bbdb/gnus-summary-prefer-bbdb-data is nil, then this has no effect. +See `bbdb/gnus-lines-and-from' for GNUS users, or +`bbdb/gnus-summary-user-format-letter' for Gnus users." + :group 'bbdb-mua-specific-gnus + :type '(choice (const :tag "Prefer real names" t) + (const :tag "Prefer network addresses" nil))) +(defvaralias 'bbdb/gnus-header-prefer-real-names + 'bbdb/gnus-summary-prefer-real-names) + +(defcustom bbdb/gnus-summary-user-format-letter "B" + "This is the gnus-user-format-function- that will be used to insert +the information from the BBDB in the summary buffer (using +`bbdb/gnus-summary-get-author'). This format code is meant to replace +codes that insert sender names or addresses (like %A or %n). Unless +you've already got other code using user format B, you might as well +stick with the default. Additionally, if the value of this variable +is nil, no format function will be installed for +`bbdb/gnus-summary-get-author'. See also +`bbdb/gnus-summary-in-bbdb-format-letter', which installs a format +code for `bbdb/gnus-summary-author-in-bbdb'" + :group 'bbdb-mua-specific-gnus + :type 'character) + +(defcustom bbdb/gnus-summary-in-bbdb-format-letter "b" + "This is the gnus-user-format-function- that will be used to insert +`bbdb/gnus-summary-known-poster-mark' (using +`bbdb/gnus-summary-author-in-bbdb') if the poster is in the BBDB, and +\" \" if not. If the value of this variable is nil, no format code +will be installed for `bbdb/gnus-summary-author-in-bbdb'. See also +`bbdb/gnus-summary-user-format-letter', which installs a format code +for `bbdb/gnus-summary-get-author'." + :group 'bbdb-mua-specific-gnus + :type 'character) + +(defcustom bbdb-message-marker-field 'mark-char + "*The field whose value will be used to mark messages by this user in Gnus." + :group 'bbdb-mua-specific-gnus + :type 'symbol) + +(defun bbdb/gnus-summary-get-author (header) + "Given a Gnus message header, returns the appropriate piece of +information to identify the author in a Gnus summary line, depending on +the settings of the various configuration variables. See the +documentation for the following variables for more details: + `bbdb/gnus-summary-mark-known-posters' + `bbdb/gnus-summary-known-poster-mark' + `bbdb/gnus-summary-prefer-bbdb-data' + `bbdb/gnus-summary-prefer-real-names' +This function is meant to be used with the user function defined in + `bbdb/gnus-summary-user-format-letter'" + (let* ((from (mail-header-from header)) + (data (and bbdb/gnus-summary-show-bbdb-names + (condition-case nil + (mail-extract-address-components from) + (error nil)))) + (name (car data)) + (net (car (cdr data))) + (record (and data + (bbdb-search-simple + name + (if (and net bbdb-canonicalize-net-hook) + (bbdb-canonicalize-address net) + net))))) + (if (and record name (member (downcase name) (bbdb-record-net record))) + ;; bogon! + (setq record nil)) + (setq name + (or (and bbdb/gnus-summary-prefer-bbdb-data + (or (and bbdb/gnus-summary-prefer-real-names + (and record (bbdb-record-name record))) + (and record (bbdb-record-net record) + (nth 0 (bbdb-record-net record))))) + (and bbdb/gnus-summary-prefer-real-names + (or (and (equal bbdb/gnus-summary-prefer-real-names 'bbdb) + net) + name)) + net from "**UNKNOWN**")) + (format "%s%s" + (or (and record bbdb/gnus-summary-mark-known-posters + (or (bbdb-record-getprop + record bbdb-message-marker-field) + bbdb/gnus-summary-known-poster-mark)) + " ") + name))) + +;; DEBUG: (bbdb/gnus-summary-author-in-bbdb "From: simmonmt@acm.org") +(defun bbdb/gnus-summary-author-in-bbdb (header) + "Given a Gnus message header, returns a mark if the poster is in the BBDB, \" \" otherwise. The mark itself is the value of the field indicated by `bbdb-message-marker-field' (`mark-char' by default) if the indicated field is in the poster's record, and `bbdb/gnus-summary-known-poster-mark' otherwise." + (let* ((from (mail-header-from header)) + (data (condition-case () + (mail-extract-address-components from) + (error nil))) + (name (car data)) + (net (cadr data)) + record) + (if (and data + (setq record + (bbdb-search-simple + name (if (and net bbdb-canonicalize-net-hook) + (bbdb-canonicalize-address net) + net)))) + (or (bbdb-record-getprop + record bbdb-message-marker-field) + bbdb/gnus-summary-known-poster-mark) " "))) + +;; +;; Gnus-specific snarfing (see also bbdb-snarf.el) +;; + +;;;###autoload +(defun bbdb/gnus-snarf-signature () + "Snarf signature from the corresponding *Article* buffer." + (interactive) + (save-excursion + ;; this is a little bogus, since it will remain set after you've + ;; quit Gnus + (or gnus-article-buffer (error "Not in Gnus!")) + ;; This is wrong for non-ASCII text. Why not use + ;; gnus-article-hide-signature? + (set-buffer gnus-original-article-buffer) + (save-restriction + (or (gnus-article-narrow-to-signature) (error "No signature!")) + (bbdb-snarf-region (point-min) (point-max))))) + +;; +;; Scoring +;; + +(defcustom bbdb/gnus-score-field 'gnus-score + "This variable contains the name of the BBDB field which should be +checked for a score to add to the net addresses in the same record." + :group 'bbdb-mua-specific-gnus-scoring + :type 'symbol) + +(defcustom bbdb/gnus-score-default nil + "If this is set, then every net address in the BBDB that does not have +an associated score field will be assigned this score. A value of nil +implies a default score of zero." + :group 'bbdb-mua-specific-gnus-scoring + :type '(choice (const :tag "Do not assign default score") + (integer :tag "Assign this default score" 0))) + +(defvar bbdb/gnus-score-default-internal nil + "Internal variable for detecting changes to +`bbdb/gnus-score-default'. You should not set this variable directly - +set `bbdb/gnus-score-default' instead.") + +(defvar bbdb/gnus-score-alist nil + "The text version of the scoring structure returned by +bbdb/gnus-score. This is built automatically from the BBDB.") + +(defvar bbdb/gnus-score-rebuild-alist t + "Set to t to rebuild bbdb/gnus-score-alist on the next call to +bbdb/gnus-score. This will be set automatically if you change a BBDB +record which contains a gnus-score field.") + +(defun bbdb/gnus-score-invalidate-alist (rec) + "This function is called through `bbdb-after-change-hook', +and sets `bbdb/gnus-score-rebuild-alist' to t if the changed +record contains a gnus-score field." + (if (bbdb-record-getprop rec bbdb/gnus-score-field) + (setq bbdb/gnus-score-rebuild-alist t))) + +;;;###autoload +(defun bbdb/gnus-score (group) + "This returns a score alist for GNUS. A score pair will be made for +every member of the net field in records which also have a gnus-score +field. This allows the BBDB to serve as a supplemental global score +file, with the advantage that it can keep up with multiple and changing +addresses better than the traditionally static global scorefile." + (list (list + (condition-case nil + (read (bbdb/gnus-score-as-text group)) + (error (setq bbdb/gnus-score-rebuild-alist t) + (message "Problem building BBDB score table.") + (ding) (sit-for 2) + nil))))) + +(defun bbdb/gnus-score-as-text (group) + "Returns a SCORE file format string built from the BBDB." + (cond ((or (cond ((/= (or bbdb/gnus-score-default 0) + (or bbdb/gnus-score-default-internal 0)) + (setq bbdb/gnus-score-default-internal + bbdb/gnus-score-default) + t)) + (not bbdb/gnus-score-alist) + bbdb/gnus-score-rebuild-alist) + (setq bbdb/gnus-score-rebuild-alist nil) + (setq bbdb/gnus-score-alist + (concat "((touched nil) (\"from\"\n" + (mapconcat + (lambda (rec) + (let ((score (or (bbdb-record-getprop rec + bbdb/gnus-score-field) + bbdb/gnus-score-default)) + (net (bbdb-record-net rec))) + (if (not (and score net)) nil + (mapconcat + (lambda (addr) + (format "(\"%s\" %s)\n" addr score)) + net "")))) + (bbdb-records) "") + "))")))) + bbdb/gnus-score-alist) + +;;;###autoload +(defun bbdb/gnus-summary-show-all-recipients (not-elided) + "Display BBDB records for all recipients of the message." + (interactive "P") + (let ((bbdb-display-layout (or (not not-elided) + bbdb-pop-up-display-layout + bbdb-display-layout)) + (bbdb-get-only-first-address-p nil)) + (gnus-summary-select-article) + (bbdb/gnus-show-records 'recipients))) + +;;; from Brian Edmonds' gnus-bbdb.el +;;; +;;; Filing with gnus-folder REQUIRES (ding) 0.50 OR HIGHER +;;; +;;; To use this feature, you need to put this file somewhere in your +;;; load-path and add the following lines of code to your .gnus file: +;;; +;;; (setq nnmail-split-methods 'bbdb/gnus-split-method) +;;; +;;; You should also examine the variables defvar'd below and customize +;;; them to your taste. They're listed roughly in descending likelihood +;;; of your wanting to change them. Once that is done, you need to add +;;; filing information to your BBDB. There are two fields of interest: +;;; +;;; 1. gnus-private. This field contains the name of the group in which +;;; mail to you from any of the addresses associated with this record +;;; will be filed. Also, any self-copies of mail you send any of the +;;; same addresses will be filed here. +;;; 2. gnus-public. This field is used to keep mail from mailing lists +;;; out of the private mailboxes. It should be added to a record for +;;; the list submission address, and is formatted as follows: +;;; "group regexp" +;;; where group is where mail from the list should be filed, and +;;; regexp is a regular expression which is checked against the +;;; envelope sender (from the From_ header) to verify that this is +;;; the copy which came from the list. For example, the entry for +;;; the ding mailing list might be: +;;; "mail.emacs.ding ding-request@ifi.uio.no" +;;; Yes, the second part *is* a regexp, so those dots may match +;;; something other than dots. Sue me. +;;; +;;; Note that you can also specify a gnus-private field for mailing list +;;; addresses, in which case self-copies of mail you send to the list +;;; will be filed there. Also, the field names can be changed below if +;;; the defaults aren't hip enough for you. Lastly, if you specify a +;;; gnus-private field for your *own* BBDB record, then all self-copies +;;; of mail you send will be filed to that group. +;;; +;;; This documentation should probably be expanded and moved to a +;;; separate file, but it's late, and *I* know what I'm trying to +;;; say. :) + +;;; custom bits +(defcustom bbdb/gnus-split-default-group "mail.misc" + "*If the BBDB doesn't indicate any group to spool a message to, it will +be spooled to this group. If bbdb/gnus-split-crosspost-default is not +nil, and if the BBDB did not indicate a specific group for one or more +addresses, messages will be crossposted to this group in addition to any +group(s) which the BBDB indicated." + :group 'bbdb-mua-specific-gnus-splitting + :type 'string) + +(defcustom bbdb/gnus-split-nomatch-function nil + "*This function will be called after searching the BBDB if no place to +file the message could be found. It should return a group name (or list +of group names) -- nnmail-split-fancy as provided with Gnus is an +excellent choice." + :group 'bbdb-mua-specific-gnus-splitting + :type 'function) + +(defcustom bbdb/gnus-split-myaddr-regexp + (concat "^" (user-login-name) "$\\|^" + (user-login-name) "@\\([-a-z0-9]+\\.\\)*" + (or gnus-local-domain (message-make-domain) + (system-name) "") "$") + "*This regular expression should match your address as found in the +From header of your mail. You should make sure gnus-local-domain or +gnus-use-generic-from are set before loading this module, if they differ +from (system-name). If you send mail/news from multiple addresses, then +you'll likely have to set this yourself anyways." + :group 'bbdb-mua-specific-gnus-splitting + :type 'string) + +(defcustom bbdb/gnus-split-crosspost-default nil + "*If this variable is not nil, then if the BBDB could not identify a +group for every mail address, messages will be filed in +bbdb/gnus-split-default-group in addition to any group(s) which the BBDB +identified." + :group 'bbdb-mua-specific-gnus-splitting + :type 'boolean) + +(defcustom bbdb/gnus-split-private-field 'gnus-private + "*This variable is used to determine the field to reference to find the +associated group when saving private mail for a network address known to +the BBDB. The value of the field should be the name of a mail group." + :group 'bbdb-mua-specific-gnus-splitting + :type 'string) + +(defcustom bbdb/gnus-split-public-field 'gnus-public + "*This variable is used to determine the field to reference to find the +associated group when saving non-private mail (received from a mailing +list) for a network address known to the BBDB. The value of the field +should be the name of a mail group, followed by a space, and a regular +expression to match on the envelope sender to verify that this mail came +from the list in question." + :group 'bbdb-mua-specific-gnus-splitting + :type 'string) + +;; The split function works by assigning one of four spooling priorities +;; to each group that is associated with an address in the message. The +;; priorities are assigned as follows: +;; +;; 0. This priority is assigned when crosspost-default is nil to To/Cc +;; addresses which have no private group defined in the BBDB. If the +;; user's own address has no private group defined, then it will +;; always be given this priority. +;; 1. This priority is assigned to To/Cc addresses which have a private +;; group defined in the BBDB. If crosspost-default is not nil, then +;; To/Cc addresses which have no private group will also be assigned +;; this priority. This is also assigned to the user's own address in +;; the From position if a private group is defined for it. +;; 2. This priority is assigned to From addresses which have a private +;; group defined in the BBDB, except for the user's own address as +;; described under priorities 0 and 1. +;; 3. This priority is assigned to To/Cc addresses which have a public +;; group defined in the BBDB, and whose associated regular expression +;; matches the envelope sender (found in the header From_). +;; +;; The split function evaluates the spool priority for each address in +;; the headers of the message, and returns as a list all the groups +;; associated with the addresses which share the highest calculated +;; priority. + +;;;#autoload +(defun bbdb/gnus-split-method nil + "This function expects to be called in a buffer which contains a mail +message to be spooled, and the buffer should be narrowed to the message +headers. It returns a list of groups to which the message should be +spooled, using the addresses in the headers and information from the +BBDB." + (let ((prq (list (cons 0 nil) (cons 1 nil) (cons 2 nil) (cons 3 nil)))) + ;; the From: header is special + (let* ((hdr (or (mail-fetch-field "resent-from") + (mail-fetch-field "from") + (user-login-name))) + (rv (bbdb/gnus-split-to-group hdr t))) + (setcdr (nth (cdr rv) prq) (cons (car rv) nil))) + ;; do the rest of the headers + (let ((hdr (or (concat (or (mail-fetch-field "resent-to" nil t) + (mail-fetch-field "to" nil t)) + ", " + (mail-fetch-field "cc" nil t) + ", " + (mail-fetch-field "apparently-to" nil t)) + ""))) + (setq hdr (rfc822-addresses hdr)) + (while hdr + (let* ((rv (bbdb/gnus-split-to-group (car hdr))) + (pr (nth (cdr rv) prq))) + (or (member (car rv) pr) (setcdr pr (cons (car rv) (cdr pr))))) + (setq hdr (cdr hdr)))) + ;; find the highest non-empty queue + (setq prq (reverse prq)) + (while (and prq (not (cdr (car prq)))) (setq prq (cdr prq))) + ;; and return... + (if (not (or (not (cdr (car prq))) + (and (equal (cdr (car prq)) (list bbdb/gnus-split-default-group)) + (symbolp bbdb/gnus-split-nomatch-function) + (fboundp bbdb/gnus-split-nomatch-function)))) + (cdr (car prq)) + (goto-char (point-min)) + (funcall bbdb/gnus-split-nomatch-function)))) + +(defun bbdb/gnus-split-to-group (addr &optional source) + "This function is called from bbdb/gnus-split-method in order to +determine the group and spooling priority for a single address." + (condition-case tmp + (progn + (setq tmp (mail-extract-address-components addr)) + (let* ((nam (car tmp)) + (net (if (not bbdb-canonicalize-net-hook) (car (cdr tmp)) + (bbdb-canonicalize-address (car (cdr tmp))))) + (rec (bbdb-search-simple nam net)) + pub prv rgx) + (if (not rec) nil + (setq prv (bbdb-record-getprop rec bbdb/gnus-split-private-field) + pub (bbdb-record-getprop rec bbdb/gnus-split-public-field)) + (if (and pub (not source) (string-match "^\\([^ ]+\\) \\(.*\\)$" pub)) + (setq rgx (substring pub (match-beginning 2) (match-end 2)) + pub (substring pub (match-beginning 1) (match-end 1))) + (setq pub nil))) + (cond + ((and rgx pub + (goto-char (point-min)) + (re-search-forward "^From: \\([^ \n]+\\)[ \n]" nil t) + (string-match rgx (buffer-substring (match-beginning 1) + (match-end 1)))) + (cons pub 3)) + (prv + (cons prv + (- 1 (if source -1 0) + (if (string-match bbdb/gnus-split-myaddr-regexp net) 1 0)))) + (t + (cons bbdb/gnus-split-default-group + (if (string-match bbdb/gnus-split-myaddr-regexp net) 0 + (if source 2 (if bbdb/gnus-split-crosspost-default 1 0)))))))) + (error (cons bbdb/gnus-split-default-group 0)))) + +;; +;; Insinuation +;; + +;;;###autoload +(defun bbdb-insinuate-gnus () + "Call this function to hook BBDB into GNUS." + (setq gnus-optional-headers 'bbdb/gnus-lines-and-from) + (add-hook 'gnus-article-prepare-hook 'bbdb/gnus-pop-up-bbdb-buffer) + (add-hook 'gnus-save-newsrc-hook 'bbdb-offer-save) + (define-key gnus-summary-mode-map ":" 'bbdb/gnus-show-sender) + (define-key gnus-summary-mode-map ";" 'bbdb/gnus-edit-notes) + + ;; Set up user field for use in gnus-summary-line-format + (let ((get-author-user-fun (intern + (concat "gnus-user-format-function-" + bbdb/gnus-summary-user-format-letter))) + (in-bbdb-user-fun (intern + (concat "gnus-user-format-function-" + bbdb/gnus-summary-in-bbdb-format-letter)))) + ; The big one - whole name + (cond (bbdb/gnus-summary-user-format-letter + (if (and (fboundp get-author-user-fun) + (not (eq (symbol-function get-author-user-fun) + 'bbdb/gnus-summary-get-author))) + (bbdb-warn + (format "`gnus-user-format-function-%s' already seems to be in use. +Please redefine `bbdb/gnus-summary-user-format-letter' to a different letter." + bbdb/gnus-summary-user-format-letter)) + (fset get-author-user-fun 'bbdb/gnus-summary-get-author)))) + + ; One tick. One tick only, please + (cond (bbdb/gnus-summary-in-bbdb-format-letter + (if (and (fboundp in-bbdb-user-fun) + (not (eq (symbol-function in-bbdb-user-fun) + 'bbdb/gnus-summary-author-in-bbdb))) + (bbdb-warn + (format "`gnus-user-format-function-%s' already seems to be in use. +Redefine `bbdb/gnus-summary-in-bbdb-format-letter' to a different letter." + bbdb/gnus-summary-in-bbdb-format-letter)) + (fset in-bbdb-user-fun 'bbdb/gnus-summary-author-in-bbdb))))) + + ;; Scoring + (add-hook 'bbdb-after-change-hook 'bbdb/gnus-score-invalidate-alist) +; (setq gnus-score-find-score-files-function +; (if (boundp 'gnus-score-find-score-files-function) +; (cond ((functionp gnus-score-find-score-files-function) +; (list gnus-score-find-score-files-function +; 'bbdb/gnus-score)) +; ((listp gnus-score-find-score-files-function) +; (append gnus-score-find-score-files-function +; 'bbdb/gnus-score)) +; (t 'bbdb/gnus-score)) +; 'bbdb/gnus-score)) + ) + +;; Uwe Brauer +(defun bbdb/gnus-nnimap-folder-list-from-bbdb () + "Return a list of \( \"From\" email-regexp imap-folder-name\) tuples +based on the contents of the bbdb. + +The folder-name is the value of the 'imap attribute on the bbdb +record; the email-regexp consists of all the email addresses for the +bbdb record concatenated with with OR. bbdb records without a 'imap +attribute are ignored. +Here is an example of a relevant BBDB entry: + +Uwe Brauer + net: oub@mat.ucm.es + imap: testimap + + +This function uses regexp-opt to generate the email-regexp which +automatically regexp-quotes its arguments. Please note: in oder that +this will work with the nnimap-split-fancy method you have to use +macros, that is your setting will look like: + +\(setq + nnimap-split-rule 'nnimap-split-fancy + nnimap-split-inbox \"INBOX\" + nnimap-split-fancy + `\(| + ,@\(bbdb/gnus-nnimap-folder-list-from-bbdb\) + ... +\)\) +Note that `\( is the backquote NOT the quote '\(. " + + ;(interactive) + (let ( ;; the raw-notes attribute of a bbdb record + notes-attr + ;; the value of the 'imap attribute of a bbdb record + folder-attr + ;; strings to put before and after the folder-attr + (folder-prefix "") + (folder-postfix "") + ;; a regexp matching all the email addresses from a bbdb record + email-regexp + ;; the list of (folder email) tuples to return + new-elmnt-list + ) + ;; loop over the bbdb-records; if a imap attribute exists on + ;; the record, generate a regexp matching all the email addresses + ;; and add a tuple (folder email-regexp) to the new-elmnt-list + (dolist (record (bbdb-records)) + (setq notes-attr (bbdb-record-raw-notes record)) + (when (and (listp notes-attr) + (setq folder-attr (cdr (assq 'imap notes-attr)))) + (setq email-regexp (regexp-opt (mapcar 'downcase + (bbdb-record-net record)))) + (unless (zerop (length email-regexp)) + (setq new-elmnt-list + (cons (list "From" email-regexp (concat folder-prefix + folder-attr folder-postfix)) + new-elmnt-list))))) + new-elmnt-list)) + + +(provide 'bbdb-gnus) diff --git a/xemacs-packages/lisp/bbdb/bbdb-gnus.elc b/xemacs-packages/lisp/bbdb/bbdb-gnus.elc new file mode 100644 index 0000000000000000000000000000000000000000..af0b4380ae12c0bbfdebbedf7dbef16b0f841cae GIT binary patch literal 24500 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. + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; This code is kind of kludgey, mostly because it needs to parse the contents +;;; of the *BBDB* buffer, since BBDB doesn't save the buffer-positions of the +;;; various fields when it fills in that buffer (doing that would be slow and +;;; cons a lot, so it doesn't seem to be worth it.) + +(require 'bbdb) +(require 'bbdb-com) + +;; compiler whinage. Some of this is legacy stuff that would probably +;; be better deleted. +(defvar scrollbar-height nil) + +;; MIGRATE XXX +(eval-and-compile + (if (fboundp 'set-specifier) + (defalias 'bbdb-set-specifier 'set-specifier) + (defalias 'bbdb-set-specifier 'ignore)) + (if (fboundp 'make-glyph) + (defalias 'bbdb-make-glyph 'make-glyph) + (defalias 'bbdb-make-glyph 'ignore)) + (if (fboundp 'set-glyph-face) + (defalias 'bbdb-set-glyph-face 'set-glyph-face) + (defalias 'bbdb-set-glyph-face 'ignore)) + (if (fboundp 'highlight-headers-x-face) + (defalias 'bbdb-highlight-headers-x-face 'highlight-headers-x-face) + (defalias 'bbdb-highlight-headers-x-face 'ignore)) + (if (fboundp 'highlight-headers-x-face-to-pixmap) + (defalias 'bbdb-highlight-headers-x-face-to-pixmap + 'highlight-headers-x-face-to-pixmap) + (defalias 'bbdb-highlight-headers-x-face-to-pixmap 'ignore))) + + +(if (featurep 'xemacs) + (progn + (define-key bbdb-mode-map 'button3 'bbdb-menu) + (define-key bbdb-mode-map 'button2 + (lambda (e) + (interactive "e") + (mouse-set-point e) + (bbdb-toggle-records-display-layout nil)))) + (define-key bbdb-mode-map [mouse-3] 'bbdb-menu) + (define-key bbdb-mode-map [mouse-2] + (lambda (e) + (interactive "e") + (mouse-set-point e) + (bbdb-toggle-records-display-layout nil)))) + +(eval-and-compile + (if (fboundp 'find-face) + (defalias 'bbdb-find-face 'find-face) + (if (fboundp 'internal-find-face) ;; GRR. + ;; This should be facep in Emacs 21 + (defalias 'bbdb-find-face 'internal-find-face) + (defalias 'bbdb-find-face 'ignore)))) ; noop - you probably don't HAVE faces. + +(or (bbdb-find-face 'bbdb-name) + (face-differs-from-default-p (make-face 'bbdb-name)) + (set-face-underline-p 'bbdb-name t)) + +(condition-case nil + (or (bbdb-find-face 'bbdb-company) + (face-differs-from-default-p (make-face 'bbdb-company)) + (make-face-italic 'bbdb-company)) ;; this can fail on emacs + (error nil)) + +(or (bbdb-find-face 'bbdb-field-value) + (make-face 'bbdb-field-value)) + +(or (bbdb-find-face 'bbdb-field-name) + (face-differs-from-default-p (make-face 'bbdb-field-name)) + (copy-face 'bold 'bbdb-field-name)) + +;;; Extents vs. Overlays unhappiness +;;; FIXME: see if VM is around, and call its extents code instead; +;;; change bbdb-foo-extents below to vm-foo-extents, etc. +(eval-and-compile + (if (fboundp 'make-extent) + (defalias 'bbdb-make-extent 'make-extent) + (defalias 'bbdb-make-extent 'make-overlay)) + + (if (fboundp 'delete-extent) + (defalias 'bbdb-delete-extent 'delete-extent) + (defalias 'bbdb-delete-extent 'delete-overlay)) + + (if (fboundp 'mapcar-extents) + (defmacro bbdb-list-extents() `(mapcar-extents 'identity)) + (defun bbdb-list-extents() + (let ((o (overlay-lists))) (nconc (car o) (cdr o))))) + + (if (fboundp 'mapcar-extents) + (defmacro bbdb-extents-in (s e) + (list 'mapcar-extents ''identity nil nil s e)) + (defmacro bbdb-extents-in (s e) + (list 'overlays-in s e))) + + (if (fboundp 'set-extent-property) + (defalias 'bbdb-set-extent-property 'set-extent-property) + (defun bbdb-set-extent-property( e p v ) + (if (eq 'highlight p) + (if v + (overlay-put e 'mouse-face 'highlight) + (overlay-put e 'mouse-face nil))) + (overlay-put e p v))) + + (if (fboundp 'extent-property) + (defalias 'bbdb-extent-property 'extent-property) + (defalias 'bbdb-extent-property 'overlay-get)) + + (if (fboundp 'extent-at) + (defalias 'bbdb-extent-at 'extent-at) + (defun bbdb-extent-at (pos buf tag) "NOT FULL XEMACS IMPLEMENTATION" + (let ((o (overlays-at pos)) + minpri retval) + (while (car o) + (let ((x (car o))) + (and (overlayp x) + (overlay-get x tag) + (if (or (null minpri) (> minpri (overlay-get x 'priority))) + (setq retval x + minpri (overlay-get x 'priority)))) + (setq o (cdr o)))) + retval))) + + (if (fboundp 'highlight-extent) + (defalias 'bbdb-highlight-extent 'highlight-extent) + (defalias 'bbdb-highlight-extent 'ignore)) ; XXX noop + + (if (fboundp 'extent-start-position) + (defalias 'bbdb-extent-start-position 'extent-start-position) + (defalias 'bbdb-extent-start-position 'overlay-start)) + + (if (fboundp 'extent-end-position) + (defalias 'bbdb-extent-end-position 'extent-end-position) + (defalias 'bbdb-extent-end-position 'overlay-end)) + + (if (fboundp 'extent-face) + (defalias 'bbdb-extent-face 'extent-face) + (defun bbdb-extent-face (extent) + (overlay-get extent 'face))) + + (if (fboundp 'set-extent-face) + (defalias 'bbdb-set-extent-face 'set-extent-face) + (defun bbdb-set-extent-face (extent face) "set the face for an overlay" + (overlay-put extent 'face face))) + + (if (fboundp 'set-extent-begin-glyph) + (defalias 'bbdb-set-extent-begin-glyph 'set-extent-begin-glyph) + (defalias 'bbdb-set-extent-begin-glyph 'ignore)) ; XXX noop + + (if (fboundp 'set-extent-end-glyph) + (defalias 'bbdb-set-extent-end-glyph 'set-extent-end-glyph) + (defalias 'bbdb-set-extent-end-glyph 'ignore))) ; XXX noop + + +(eval-when-compile (defvar scrollbar-height)) +;;;###autoload +(defun bbdb-fontify-buffer (&optional records) + (interactive) + (save-excursion + (set-buffer bbdb-buffer-name) + (if (featurep 'scrollbar) + (bbdb-set-specifier scrollbar-height (cons (current-buffer) 0))) + + (let ((rest (or records bbdb-records)) + record face + start end s e + multi-line-p + property + extent) + + (while rest + (setq record (car (car rest)) + multi-line-p (string-match "multi-line" + (symbol-name (nth 1 (car rest)))) + face (and multi-line-p (bbdb-record-getprop record 'face)) + start (marker-position (nth 2 (car rest))) + end (1- (or (nth 2 (car (cdr rest))) (point-max)))) + + (if (< start (point-min)) (setq start (point-min))) + (if (> end (point-max)) (setq end (point-max))) + + (mapcar (function (lambda(o) + (if (and o + (eq (bbdb-extent-property o 'data) + 'bbdb)) + (bbdb-delete-extent o)))) + (bbdb-extents-in start end)) + + (setq extent (bbdb-make-extent start end)) + (bbdb-set-extent-property extent 'highlight t) + (bbdb-set-extent-property extent 'data 'bbdb) + ;; note that on GNU Emacs, once you hit the main overlay, you + ;; have to move off the record and back on again before it'll + ;; notice that you're on a more specific overlay. This is + ;; bogus, like most GNU Emacs GUI stuff. + (bbdb-set-extent-property extent 'priority 3) + (if face (bbdb-hack-x-face face extent)) + (goto-char start) + (setq s start) + (setq property (cadr (member 'bbdb-field (text-properties-at s)))) + (while (and s (< s end)) + (setq e (or (next-single-property-change (1+ s) 'bbdb-field) + (point-max))) + (cond ((equal property '(name)) + (setq extent (bbdb-make-extent s e)) + (bbdb-set-extent-property extent 'priority 2) + (bbdb-set-extent-property extent 'data 'bbdb) + (bbdb-set-extent-face extent 'bbdb-name)) + ((equal property '(company)) + (setq extent (bbdb-make-extent s e)) + (bbdb-set-extent-property extent 'priority 2) + (bbdb-set-extent-property extent 'data 'bbdb) + (bbdb-set-extent-face extent 'bbdb-company)) + ((member 'field-name property) + (goto-char s) + (setq extent (bbdb-make-extent s e)) + (bbdb-set-extent-property extent 'priority 2) + (bbdb-set-extent-property extent 'data 'bbdb) + (bbdb-set-extent-face extent 'bbdb-field-name)) + (t + (setq extent (bbdb-make-extent start e)) + (bbdb-set-extent-property extent 'priority 2) + (bbdb-set-extent-property extent 'data 'bbdb) + (bbdb-set-extent-face extent 'bbdb-field-value))) + (setq s e) + (while (and s (null (setq property + (cadr (member 'bbdb-field + (text-properties-at s)))))) + (setq s (next-single-property-change s 'bbdb-field)))) + + (setq rest (cdr rest)) + (if (null (caar rest)) + (setq rest nil)))))) + +;;; share the xface cache data with VM if it's around +(defvar vm-xface-cache (make-vector 29 0)) +(eval-when-compile (defvar highlight-headers-hack-x-face-p)) + +;; In Emacs 21, this could use the x-face support from Gnus. +(defun bbdb-hack-x-face (face extent) + "Process a face property of a record and honour it. +Not done for GNU Emacs just yet, since it doesn't have image support +as of GNU Emacs 20.7" + (if (not (or (and (fboundp 'highlight-headers-hack-x-face-p) + (symbol-value (intern ;; compiler + "highlight-headers-hack-x-face-p"))) ;; ick. + (and (featurep 'xemacs) + (string-match "^21\\." emacs-version)))) ;; XXX + () ;; nothing doing + (setq face (bbdb-split face "\n")) + (while face + (cond + + ;; ripped pretty much verbatim from VM; X Faces for recent XEmacsen. + ((string-match "^21\\." emacs-version) ;; XXX how far back can I go? + (condition-case nil + (let* ((h (concat "X-Face: " (car face))) ;; from vm-display-xface + (g (intern h vm-xface-cache))) + (if (bbdb-find-face 'vm-xface) ;; use the same face as VM + nil + (make-face 'vm-xface) + (set-face-background 'vm-xface "white") + (set-face-foreground 'vm-xface "black")) + (if (boundp g) + (setq g (symbol-value g)) + (set g (bbdb-make-glyph + (list + (vector 'xface ':data h)))) ;; XXX use API + (setq g (symbol-value g)) + (bbdb-set-glyph-face g 'vm-xface)) + (bbdb-set-extent-property extent 'vm-xface t) + (bbdb-set-extent-begin-glyph extent g)) + (error nil))) ;; looks like you don't have xface support, d00d + + ;; requires lemacs 19.10 version of highlight-headers.el + ((fboundp 'highlight-headers-x-face) ; the 19.10 way + (bbdb-highlight-headers-x-face (car face) extent) + (let ((b (bbdb-extent-property extent 'begin-glyph))) + (cond (b ; I'd like this to be an end-glyph instead + (bbdb-set-extent-property extent 'begin-glyph nil) + (bbdb-set-extent-property extent 'end-glyph b))))) + + ((fboundp 'highlight-headers-x-face-to-pixmap) ; the 19.13 way + (save-excursion + (set-buffer (get-buffer-create " *tmp*")) + (buffer-disable-undo (current-buffer)) + (erase-buffer) + (insert (car face)) + (bbdb-set-extent-begin-glyph extent nil) + (bbdb-set-extent-end-glyph extent + (bbdb-highlight-headers-x-face-to-pixmap + (point-min) (point-max))) + (erase-buffer)))) + + ;; more faces? + (setq face (cdr face)) + (cond (face ; there are more, so clone the extent + (setq extent (bbdb-make-extent + (bbdb-extent-start-position extent) + (bbdb-extent-end-position extent))) + (bbdb-set-extent-property extent 'data 'bbdb)))))) + + +(defcustom bbdb-user-menu-commands nil + "User defined menu entries which should be appended to the BBDB menu. +This should be a list of menu entries. +When set to a fucntion the function gets called with two arguments the +RECORD and the FIELD and it should either return nil or a list of menu +entries." + :group 'bbdb-database + :type 'sexp) + +(defun build-bbdb-finger-menu (record) + (let ((addrs (bbdb-record-finger-host record))) + (if (cdr addrs) + (cons "Finger..." + (nconc + (mapcar (lambda (addr) + (vector addr (list 'bbdb-finger record addr) + t)) + addrs) + (list "----" + (vector "Finger all addresses" + (list 'bbdb-finger record ''(4)) t)))) + (vector (concat "Finger " (car addrs)) + (list 'bbdb-finger record (car addrs)) t)))) + +(defun build-bbdb-sendmail-menu (record) + (let ((addrs (bbdb-record-net record))) + (if (cdr addrs) + (cons "Send Mail..." + (mapcar (lambda (addr) + (vector addr (list 'bbdb-send-mail-internal + (bbdb-dwim-net-address record addr)) + t)) + addrs)) + (vector (concat "Send mail to " (car addrs)) + (list 'bbdb-send-mail-internal + (bbdb-dwim-net-address record (car addrs))) + t)))) + + +(defun build-bbdb-field-menu (record field) + (let ((type (car field))) + (nconc + (list + (concat "Commands for " + (cond ((eq type 'property) + (concat "\"" + (symbol-name (if (consp (car (cdr field))) + (car (car (cdr field))) + (car (cdr field)))) + "\" field:")) + ((eq type 'name) "Name field:") + ((eq type 'company) "Company field:") + ((eq type 'net) "Network Addresses field:") + ((eq type 'aka) "Alternate Names field:") + (t + (concat "\"" (aref (nth 1 field) 0) "\" " + (capitalize (symbol-name type)) " field:")))) + "-----" + ["Edit Field" bbdb-edit-current-field t] + ) + (if (memq type '(name company)) + nil + (list ["Delete Field" bbdb-delete-current-field-or-record t])) + (cond ((eq type 'phone) + (list (vector (concat "Dial " (bbdb-phone-string (car (cdr field)))) + (list 'bbdb-dial (list 'quote field) nil) t))) + ) + ))) + + +(defun build-bbdb-insert-field-menu (record) + (cons "Insert New Field..." + (mapcar + (lambda (field) + (let ((type (if (string= (car field) "AKA") + 'aka + (intern (car field))))) + (vector (car field) + (list 'bbdb-insert-new-field + record + (list 'quote type) + (list 'bbdb-prompt-for-new-field-value + (list 'quote type))) + (not + (or (and (eq type 'net) (bbdb-record-net record)) + (and (eq type 'aka) (bbdb-record-aka record)) + (and (eq type 'notes) (bbdb-record-notes record)) + (and (consp (bbdb-record-raw-notes record)) + (assq type (bbdb-record-raw-notes record)))))))) + (append '(("phone") ("address") ("net") ("AKA") ("notes")) + (bbdb-propnames))))) + + +(defun build-bbdb-menu (record field) + (delete + nil + (append + '("bbdb-menu" "Global BBDB Commands" "-----") + (list + ["Save BBDB" bbdb-save-db t] + ["Toggle All Records Display Layout" + bbdb-toggle-all-records-display-layout t] + ["Finger All Records" (bbdb-finger (mapcar 'car bbdb-records)) t] + ["BBDB Manual" bbdb-info t] + ["BBDB Quit" bbdb-bury-buffer t]) + (if record + (list + "-----" + (concat "Commands for record \"" + (bbdb-record-name record) "\":") + "-----" + (vector "Delete Record" + (list 'bbdb-delete-current-record record) t) + ["Toggle Records Display Layout" bbdb-toggle-records-display-layout t] + (if (and (not (eq 'full-multi-line + (nth 1 (assq record bbdb-records)))) + (bbdb-display-layout-get-option 'multi-line 'omit)) + ["Fully Display Record" bbdb-display-record-completely t]) + ["Omit Record" bbdb-omit-record t] + ["Refile (Merge) Record" bbdb-refile-record t] + )) + (if record + (list (build-bbdb-finger-menu record))) + (if (bbdb-record-net record) + (list (build-bbdb-sendmail-menu record))) + (if record + (list (build-bbdb-insert-field-menu record))) + (if field + (cons "-----" (build-bbdb-field-menu record field))) + (if bbdb-user-menu-commands + (let ((menu (if (functionp bbdb-user-menu-commands) + (funcall bbdb-user-menu-commands record field) + bbdb-user-menu-commands))) + (if menu + (append ["-----"] + ["User Defined Commands"] + ["-----"] + menu))))))) + +(eval-and-compile + (if (fboundp 'popup-menu) + (progn + (fset 'bbdb-popup 'popup-menu) + (fset 'bbdb-desc-to-menu 'identity)) + ;; This is really, REALLY ugly, but it saves me some coding and uses + ;; the correct keymap API instead of carnal knowledge of keymap + ;; structure. + (defun bbdb-desc-to-menu(desc) + (let ((map (make-sparse-keymap (car desc))) + (desc (reverse (cdr desc))) ;; throw away header, reorient list + (txtcount 0) elt elt-name) + (while (setq elt (car desc)) + ;; fake a key binding name + (setq elt-name (intern (format "fake%d" txtcount)) + txtcount (+ 1 txtcount)) + (cond + ;; non-active entries in the menu + ((stringp elt) + (define-key map (vector elt-name) (list elt))) + + ;; active entries in the menu + ((vectorp elt) + (define-key map (vector elt-name) (cons (aref elt 0) (aref elt 1)))) + + ;; submenus + ((listp elt) + (define-key map (vector elt-name) + (cons (car elt) (bbdb-desc-to-menu elt)))) + ) + (setq desc (cdr desc))) + map)) + ;; this does the actual popping up & parsing nonsense + (defun bbdb-popup( desc &optional event ) + (let ((map (bbdb-desc-to-menu desc)) result) + (setq result (x-popup-menu t map)) + (if result + (let ((command (lookup-key map (vconcat result)))) + ;; Clear out echoing, which perhaps shows a prefix arg. + (message "") + (if command + (if (commandp command) + (command-execute command) + (funcall 'eval command))))))))) + +;;;###autoload +(defun bbdb-menu (event) + (interactive "e") + (mouse-set-point event) + (bbdb-popup + (save-window-excursion + (save-excursion + (let ((extent (or (bbdb-extent-at (point) (current-buffer) 'highlight) + (error ""))) + record field) + (or (eq (bbdb-extent-property extent 'data) 'bbdb) + (error "not a bbdb extent")) + (bbdb-highlight-extent extent t) + (setq record (bbdb-current-record) + field (get-text-property (point) 'bbdb-field)) + (build-bbdb-menu record field)))))) + +;; tell everyone else we're here. +(provide 'bbdb-gui) diff --git a/xemacs-packages/lisp/bbdb/bbdb-gui.elc b/xemacs-packages/lisp/bbdb/bbdb-gui.elc new file mode 100644 index 0000000000000000000000000000000000000000..ac8fd2dcf2539cba7fcaf959804a1ff2ce8c4ead GIT binary patch literal 9745 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. +;;; Various additional functionality for the BBDB. See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; This file lets you do stuff like +;;; +;;; o automatically update a "timestamp" field each time a record is +;;; modified +;;; o automatically add some string to the notes field(s) based on the +;;; contents of header fields of the current message +;;; o only automatically create entries when certain header fields +;;; are matched +;;; o don't automatically create entries when certain header fields +;;; are matched +;;; +;;; Read the docstrings; read the texinfo file. + +;; +;; $Id: bbdb-hooks.el,v 1.6 2005/07/24 15:22:57 waider Exp $ +;; + +(require 'bbdb) +(require 'bbdb-com) + +(eval-when-compile + (condition-case() + (progn + (require 'gnus) + (require 'bbdb-gnus)) + (error nil)) + (condition-case() + (progn + (require 'vm) + (require 'bbdb-vm)) + (error nil)) + (autoload 'mh-show "mh-e") + (condition-case() + (require 'bbdb-rmail) + (error nil))) + +(defvar rmail-buffer) +(defvar mh-show-buffer) + + +(defvar bbdb-time-internal-format "%Y-%m-%d" + "The internal date format.") + +;;;###autoload +(defun bbdb-timestamp-hook (record) + "For use as a `bbdb-change-hook'; maintains a notes-field called `timestamp' +for the given record which contains the time when it was last modified. If +there is such a field there already, it is changed, otherwise it is added." + (bbdb-record-putprop record 'timestamp (format-time-string + bbdb-time-internal-format + (current-time)))) + +;;;###autoload +(defun bbdb-creation-date-hook (record) + "For use as a `bbdb-create-hook'; adds a notes-field called `creation-date' +which is the current time string." + ;; hey buddy, we've known about your antics since the eighties... + (bbdb-record-putprop record 'creation-date (format-time-string + bbdb-time-internal-format + (current-time)))) + + +;;; Determining whether to create a record based on the content of the +;;; current message. + +(eval-when-compile + (defvar vm-mail-buffer) + (defvar vm-message-pointer) + (autoload 'vm-start-of "vm") + (autoload 'bbdb/vm-pop-up-bbdb-buffer "bbdb-vm")) + +;;;###autoload +(defun bbdb-header-start () + "Returns a marker at the beginning of the header block of the current +message. This will not necessarily be in the current buffer." + (cond ((memq major-mode + '(gnus-group-mode gnus-summary-mode gnus-article-mode)) + (set-buffer (or gnus-original-article-buffer + gnus-article-buffer)) + (point-min-marker)) + ((memq major-mode '(vm-presentation-mode vm-mode vm-summary-mode)) + (if vm-mail-buffer (set-buffer vm-mail-buffer)) + (vm-start-of (car vm-message-pointer))) + ((memq major-mode '(rmail-mode rmail-summary-mode)) + (if (and (boundp 'rmail-buffer) rmail-buffer) + (set-buffer rmail-buffer)) + (point-min-marker)) + ;; MH-E clause added by knabe. + ((eq major-mode 'mh-folder-mode) + (mh-show) + (set-buffer mh-show-buffer) + (point-min-marker)) + (t (point-min-marker)) + )) + + +;;;###autoload +(defun bbdb-extract-field-value (field-name) + "Given the name of a field (like \"Subject\") this returns the value of +that field in the current message, or nil. This works whether you're in +GNUS, Rmail, or VM. This works on multi-line fields, but if more than +one field of the same name is present, only the last is returned. It is +expected that the current buffer has a message in it, and (point) is at the +beginning of the message headers." + ;; we can't special-case VM here to use its cache, because the cache has + ;; divided real-names from addresses; the actual From: and Subject: fields + ;; exist only in the message. + (save-excursion + (if (memq major-mode + '(gnus-summary-mode gnus-article-mode gnus-tree-mode)) + (progn + (set-buffer (get-buffer gnus-original-article-buffer)) + (goto-char (point-min)))) + (setq field-name (concat (regexp-quote field-name) "[ \t]*:[ \t]*")) + (let ((case-fold-search t) + done) + (while (not (or done + (looking-at "\n") ; we're at BOL + (eobp))) + (if (looking-at field-name) + (progn + (goto-char (match-end 0)) + (setq done (buffer-substring (point) + (progn (end-of-line) (point)))) + (while (looking-at "\n[ \t]") + (setq done (concat done " " + (buffer-substring (match-end 0) + (progn (end-of-line 2) (point)))))))) + (forward-line 1)) + done))) + +(defcustom bbdb-ignore-most-messages-alist '() + "*An alist describing which messages to automatically create BBDB +records for. This only works if bbdb/news-auto-create-p or +bbdb/mail-auto-create-p (or both) is 'bbdb-ignore-most-messages-hook. +The format of this alist is + (( HEADER-NAME . REGEXP ) ... ) +for example, + ((\"From\" . \"@.*\\.maximegalon\\.edu\") + (\"Subject\" . \"time travel\")) +will cause BBDB entries to be made only for messages sent by people at +Maximegalon U., or (that's *or*) people posting about time travel. + +See also bbdb-ignore-some-messages-alist, which has the opposite effect." + :group 'bbdb-noticing-records + :type '(repeat (cons + (string :tag "Header name") + (regexp :tag "Regex to match on header value")))) + + +(defcustom bbdb-ignore-some-messages-alist '() + "*An alist describing which messages *not* to automatically create +BBDB records for. This only works if bbdb/news-auto-create-p or +bbdb/mail-auto-create-p (or both) is 'bbdb-ignore-some-messages-hook. +The format of this alist is + (( HEADER-NAME . REGEXP ) ... ) +for example, + ((\"From\" . \"mailer-daemon\") + (\"To\" . \"mailing-list-1\\\\|mailing-list-2\") + (\"CC\" . \"mailing-list-1\\\\|mailing-list-2\")) +will cause BBDB entries to not be made for messages from any mailer daemon, +or messages sent to or CCed to either of two mailing lists. + +See also bbdb-ignore-most-messages-alist, which has the opposite effect." + :group 'bbdb-noticing-records + :type '(repeat (cons + (string :tag "Header name") + (regexp :tag "Regex to match on header value")))) + + +;;;###autoload +(defun bbdb-ignore-most-messages-hook (&optional invert-sense) + "For use as the value of bbdb/news-auto-create-p or bbdb/mail-auto-create-p. +This will automatically create BBDB entries for messages which match +the bbdb-ignore-most-messages-alist (which see) and *no* others." + ;; don't need to optimize this to check the cache, because if + ;; bbdb/*-update-record uses the cache, this won't be called. + (let ((rest (if invert-sense + bbdb-ignore-some-messages-alist + bbdb-ignore-most-messages-alist)) + (case-fold-search t) + (done nil) + (b (current-buffer)) + (marker (bbdb-header-start)) + field regexp fieldval) + (set-buffer (marker-buffer marker)) + (save-restriction + (widen) + (while (and rest (not done)) + (goto-char marker) + (setq field (car (car rest)) + regexp (cdr (car rest)) + fieldval (bbdb-extract-field-value field)) + (if (and fieldval (string-match regexp fieldval)) + (setq done t)) + (setq rest (cdr rest)))) + (set-buffer b) + (if invert-sense + (not done) + done))) + +;;; Provided by Bill Carpenter. +(defvar bbdb-ignore-selected-messages-confirmation nil + "*If bbdb-ignore-selected-messages-hook is used as an auto-create-hook, this +variable governs whether you are prompted for creation of BBDB entries.") + +;;;###autoload +(defun bbdb-ignore-selected-messages-hook () + "For use as a bbdb/news-auto-create-hook or bbdb/mail-auto-create-hook. +This will automatically create BBDB entries for messages based on a +combination of bbdb-ignore-some-messages-alist and +bbdb-ignore-most-messages-alist. It first looks at the SOME list. If +that doesn't disqualify a message, then it looks at the MOST list. If +that qualifies the message, the record is auto-created, but a +confirmation is conditionally sought, based on the value of +`bbdb-ignore-selected-messages-confirmation'." + (if (bbdb-ignore-some-messages-hook) + ;; wasn't ruled out + (if (bbdb-ignore-most-messages-hook) + ;; was ruled in + (if bbdb-ignore-selected-messages-confirmation + (let ((case-fold-search t) + (marker (bbdb-header-start)) + record-exists from) + (save-excursion + (set-buffer (marker-buffer marker)) + (save-restriction + (widen) + (goto-char marker) + (setq from (bbdb-extract-field-value "FROM")))) + (setq record-exists (bbdb-annotate-message-sender from)) + (or record-exists + (y-or-n-p (concat "Create BBDB record from " from "? ")))) + ;; no confirmation desired so let it be + t) + nil) + nil)) + +;;;###autoload +(defun bbdb-ignore-some-messages-hook () + "For use as a `bbdb/news-auto-create-hook' or `bbdb/mail-auto-create-hook'. +This will automatically create BBDB entries for messages which do *not* +match the `bbdb-ignore-some-messages-alist' (which see)." + (bbdb-ignore-most-messages-hook t)) + + +;;; Automatically add to the notes field based on the current message. + +(defcustom bbdb-auto-notes-alist nil + "*An alist which lets you have certain pieces of text automatically added +to the BBDB record representing the sender of the current message based on +the subject or other header fields. This only works if `bbdb-notice-hook' +contains `bbdb-auto-notes-hook'. The format of this alist is + + ((HEADER-NAME [ADDRESS-CLASS-LIST] + (REGEXP . STRING) ... ) + ... ) +for example, + ((\"To\" (\"-vm@\" . \"VM mailing list\")) + (\"Subject\" (\"sprocket\" . \"mail about sprockets\") + (\"you bonehead\" . \"called me a bonehead\"))) + +will cause the text \"VM mailing list\" to be added to the notes field of +the record corresponding to anyone you get mail from via one of the VM +mailing lists. If, that is, `bbdb/mail-auto-create-p' is set such that the +record would have been created, or the record already existed. + +A ADDRESS-CLASS-LIST is optional and by default actions will be performed only +for records of authors of a message. However, by giving an list of classes +specified in `bbdb-get-addresses-headers'. Actions will then only be +performed if the currently processed email is of a class listed in +ADDRESS-CLASS-LIST. ADDRESS-CLASS-LIST might also be an alist with elements +of the form (CLASS . HEADER) which allows actions only when the current +address matches one of the elemets. + +The format of elements of this list may also be + (REGEXP FIELD-NAME STRING) +or + (REGEXP FIELD-NAME STRING REPLACE-P) +instead of + (REGEXP . STRING) + +meaning add the given string to the named field. The field-name may not +be name, address, phone, or net (builtin fields) but must be either ``notes,'' +``company,'' or the name of a user-defined note-field. + (\"pattern\" . \"string to add\") +is equivalent to + (\"pattern\" notes \"string to add\") + +STRING can contain \\& or \\N escapes like in function +`replace-match'. For example, to automatically add the contents of the +\"organization\" field of a message to the \"company\" field of a BBDB +record, you can use this: + + (\"Organization\" (\".*\" company \"\\\\&\")) + +\(Note you need two \\ to get a single \\ into a lisp string literal.\) + +If STRING is an integer N, the N'th matching subexpression is used, so +the above example could be written more efficiently as + + (\"Organization\" (\".*\" company 0)) + +If STRING is neither a string or an integer, it should be a function, which +will be called with the contents of the field. The result of that function +call is used as the field value (the returned value must be a string.) + +If REPLACE-P is t, the string replaces the old contents instead of +being appended to it. + +If multiple clauses match the message, all of the corresponding strings +will be added. + +This works for news as well. You might want to arrange for this to have +a different value when in mail as when in news. + +See also variables `bbdb-auto-notes-ignore' and `bbdb-auto-notes-ignore-all'." + :group 'bbdb-noticing-records + :type '(repeat + (bbdb-alist-with-header + (string :tag "Header name") + (repeat (choice + (cons :tag "Address Class" + (repeat (choice + (const authors) + (const recipients)))) + (cons :tag "Value Pair" + (regexp :tag "Regexp to match on header value") + (string :tag "String for notes if regexp matches")) + (list :tag "Replacement list" + (regexp :tag "Regexp to match on header value") + (choice :tag "Record field" + (const notes :tag "Notes") + (const company :tag "Company") + (symbol :tag "Other")) + (choice :tag "Regexp match" + (string :tag "Replacement string") + (integer :tag "Subexpression match") + (function :tag "Callback Function")) + (choice :tag "Replace previous contents" + (const :tag "No" nil) + (const :tag "Yes" t)))))))) + +(defcustom bbdb-auto-notes-ignore nil + "Alist of headers and regexps to ignore in `bbdb-auto-notes-hook'. +Each element looks like + + (HEADER . REGEXP) + +For example, + + (\"Organization\" . \"^Gatewayed from\\\\\|^Source only\") + +would exclude the phony `Organization:' headers in GNU mailing-lists +gatewayed to gnu.* newsgroups. Note that this exclusion applies only +to a single field, not to the entire message. For that, use the variable +`bbdb-auto-notes-ignore-all'." + :group 'bbdb-noticing-records + :type '(repeat (cons + (string :tag "Header name") + (regexp :tag "Regexp to match on header value")))) + +(defcustom bbdb-auto-notes-ignore-all nil + "Alist of headers and regexps which cause the entire message to be ignored +in `bbdb-auto-notes-hook'. Each element looks like + + (HEADER . REGEXP) + +For example, + + (\"From\" . \"BLAT\\\\.COM\") + +would exclude any notes recording for message coming from BLAT.COM. +Note that this is different from `bbdb-auto-notes-ignore', which applies +only to a particular header field, rather than the entire message." + :group 'bbdb-noticing-records + :type '(repeat (cons + (string :tag "Header name") + (regexp :tag "Regexp to match on header value")))) + + +;;;###autoload +(defun bbdb-auto-notes-hook (record) + "For use as a `bbdb-notice-hook'. This might automatically add some text +to the notes field of the BBDB record corresponding to the current record +based on the header of the current message. See the documentation for +the variables `bbdb-auto-notes-alist' and `bbdb-auto-notes-ignore'." + ;; This could stand to be faster... + ;; could optimize this to check the cache, and noop if this record is + ;; cached for any other message, but that's probably not the right thing. + (unless bbdb-readonly-p + (let ((rest bbdb-auto-notes-alist) + (ignore-all bbdb-auto-notes-ignore-all) + (case-fold-search t) + (b (current-buffer)) + (marker (bbdb-header-start)) + ignore + field pairs fieldval ; do all bindings here for speed + regexp string notes-field-name notes + replace-p) + (set-buffer (marker-buffer marker)) + (save-restriction + (widen) + (goto-char marker) + (if (and (setq fieldval (bbdb-extract-field-value "From")) + (string-match (bbdb-user-mail-names) fieldval)) + ;; Don't do anything if this message is from us. Note that we have + ;; to look at the message instead of the record, because the record + ;; will be of the recipient of the message if it is from us. + nil + ;; check the ignore-all pattern + (while (and ignore-all (not ignore)) + (goto-char marker) + (setq field (car (car ignore-all)) + regexp (cdr (car ignore-all)) + fieldval (bbdb-extract-field-value field)) + (if (and fieldval + (string-match regexp fieldval)) + (setq ignore t) + (setq ignore-all (cdr ignore-all)))) + + (unless ignore ; ignore-all matched + (while rest ; while there are still clauses in the auto-notes alist + (goto-char marker) + (setq field (car (car rest)) ; name of header, e.g., "Subject" + pairs (cdr (car rest)) ; (REGEXP . STRING) or + ; (REGEXP FIELD-NAME STRING) or + ; (REGEXP FIELD-NAME STRING REPLACE-P) + fieldval (bbdb-extract-field-value field)) ; e.g., Subject line + (when fieldval + ;; we perform the auto notes stuff only for authors of a message + ;; or if explicitly requested + (if (or (symbolp (caar pairs)) (listp (caar pairs))) + (if (or (memq bbdb-update-address-class (car pairs)) + (and (assoc bbdb-update-address-class (car pairs)) + (string= bbdb-update-address-header + (cdr (assoc bbdb-update-address-class + (car pairs)))))) + (setq pairs (cdr pairs)) + (setq pairs nil)) + (if (not (and (eq 'authors bbdb-update-address-class) + (string-match "From" bbdb-update-address-header))) + (setq pairs nil))) + + ;; now handle the remaining pairs + (while pairs + (setq regexp (car (car pairs)) + string (cdr (car pairs))) + (if (consp string) ; not just the (REGEXP . STRING) format + (setq notes-field-name (car string) + replace-p (nth 2 string) ; perhaps nil + string (nth 1 string)) + ;; else it's simple (REGEXP . STRING) + (setq notes-field-name 'notes + replace-p nil)) + (setq notes (bbdb-record-getprop record notes-field-name)) + (let ((did-match + (and (string-match regexp fieldval) + ;; make sure it is not to be ignored + (let ((re (cdr (assoc field + bbdb-auto-notes-ignore)))) + (if re + (not (string-match re fieldval)) + t))))) + ;; An integer as STRING is an index into match-data: + ;; A function as STRING calls the function on fieldval: + (if did-match + (setq string + (cond ((integerp string) ; backward compat + (substring fieldval + (match-beginning string) + (match-end string))) + ((stringp string) + (bbdb-auto-expand-newtext fieldval string)) + (t + (goto-char marker) + (let ((s (funcall string fieldval))) + (or (stringp s) + (null s) + (error "%s returned %s: not a string" + string s)) + s))))) + ;; need expanded version of STRING here: + (if (and did-match + string ; A function as STRING may return nil + (not (and notes + ;; check that STRING is not already + ;; present in the NOTES field + (string-match + (regexp-quote string) + notes)))) + (if replace-p + ;; replace old contents of field with STRING + (progn + (when (not bbdb-silent-running) + (if (eq notes-field-name 'notes) + (message "Replacing with note \"%s\"" string) + (message "Replacing field \"%s\" with \"%s\"" + notes-field-name string))) + (bbdb-record-putprop record notes-field-name string) + (bbdb-maybe-update-display record)) + ;; add STRING to old contents, don't replace + (when (not bbdb-silent-running) + (if (eq notes-field-name 'notes) + (message "Adding note \"%s\"" string) + (message "Adding \"%s\" to field \"%s\"" + string notes-field-name))) + (bbdb-annotate-notes record string notes-field-name)))) + (setq pairs (cdr pairs)))) + (setq rest (cdr rest)))))) + (set-buffer b)))) + +(defun bbdb-auto-expand-newtext (string newtext) + ;; Expand \& and \1..\9 (referring to STRING) in NEWTEXT. + ;; Note that in Emacs 18 match data are clipped to current buffer + ;; size...so the buffer had better not be smaller than STRING (arrrrggggh!!) + (let ((pos 0) + (len (length newtext)) + (expanded-newtext "")) + (while (< pos len) + (setq expanded-newtext + (concat expanded-newtext + (let ((c (aref newtext pos))) + (if (= ?\\ c) + (cond ((= ?\& (setq c (aref newtext + (setq pos (1+ pos))))) + (substring string + (match-beginning 0) + (match-end 0))) + ((and (>= c ?1) + (<= c ?9)) + ;; return empty string if N'th + ;; sub-regexp did not match: + (let ((n (- c ?0))) + (if (match-beginning n) + (substring string + (match-beginning n) + (match-end n)) + ""))) + (t (char-to-string c))) + (char-to-string c))))) + (setq pos (1+ pos))) + expanded-newtext)) + + +;;; I use this as the value of bbdb-canonicalize-net-hook; it is provided +;;; as an example for you to customize. + +(defcustom bbdb-canonical-hosts + (mapconcat 'regexp-quote + '("cs.cmu.edu" "ri.cmu.edu" "edrc.cmu.edu" "andrew.cmu.edu" + "mcom.com" "netscape.com" "cenatls.cena.dgac.fr" + "cenaath.cena.dgac.fr" "irit.fr" "enseeiht.fr" "inria.fr" + "cs.uiuc.edu" "xemacs.org") + "\\|") + "Certain sites have a single mail-host; for example, all mail originating +at hosts whose names end in \".cs.cmu.edu\" can (and probably should) be +addressed to \"user@cs.cmu.edu\" instead. This variable lists other hosts +which behave the same way." + :group 'bbdb + :type '(regexp :tag "Regexp matching sites")) + +(defmacro bbdb-match-substring (string match) + (list 'substring string + (list 'match-beginning match) (list 'match-end match))) + +;;;###autoload +(defun sample-bbdb-canonicalize-net-hook (addr) + (cond + ;; + ;; rewrite mail-drop hosts. + ;; + ((string-match + (concat "\\`\\([^@%!]+@\\).*\\.\\(" bbdb-canonical-hosts "\\)\\'") + addr) + (concat (bbdb-match-substring addr 1) (bbdb-match-substring addr 2))) + ;; + ;; Here at Lucid, our workstation names sometimes get into our email + ;; addresses in the form "jwz%thalidomide@lucid.com" (instead of simply + ;; "jwz@lucid.com"). This removes the workstation name. + ;; + ((string-match "\\`\\([^@%!]+\\)%[^@%!.]+@\\(lucid\\.com\\)\\'" addr) + (concat (bbdb-match-substring addr 1) "@" (bbdb-match-substring addr 2))) + ;; + ;; Another way that our local mailer is misconfigured: sometimes addresses + ;; which should look like "user@some.outside.host" end up looking like + ;; "user%some.outside.host" or even "user%some.outside.host@lucid.com" + ;; instead. This rule rewrites it into the original form. + ;; + ((string-match "\\`\\([^@%]+\\)%\\([^@%!]+\\)\\(@lucid\\.com\\)?\\'" addr) + (concat (bbdb-match-substring addr 1) "@" (bbdb-match-substring addr 2))) + ;; + ;; Sometimes I see addresses like "foobar.com!user@foobar.com". + ;; That's totally redundant, so this rewrites it as "user@foobar.com". + ;; + ((string-match "\\`\\([^@%!]+\\)!\\([^@%!]+[@%]\\1\\)\\'" addr) + (bbdb-match-substring addr 2)) + ;; + ;; Sometimes I see addresses like "foobar.com!user". Turn it around. + ;; + ((string-match "\\`\\([^@%!.]+\\.[^@%!]+\\)!\\([^@%]+\\)\\'" addr) + (concat (bbdb-match-substring addr 2) "@" (bbdb-match-substring addr 1))) + ;; + ;; The mailer at hplb.hpl.hp.com tends to puke all over addresses which + ;; pass through mailing lists which are maintained there: it turns normal + ;; addresses like "user@foo.com" into "user%foo.com@hplb.hpl.hp.com". + ;; This reverses it. (I actually could have combined this rule with + ;; the similar lucid.com rule above, but then the regexp would have been + ;; more than 80 characters long...) + ;; + ((string-match "\\`\\([^@!]+\\)%\\([^@%!]+\\)@hplb\\.hpl\\.hp\\.com\\'" + addr) + (concat (bbdb-match-substring addr 1) "@" (bbdb-match-substring addr 2))) + ;; + ;; Another local mail-configuration botch: sometimes mail shows up + ;; with addresses like "user@workstation", where "workstation" is a + ;; local machine name. That should really be "user" or "user@netscape.com". + ;; (I'm told this one is due to a bug in SunOS 4.1.1 sendmail.) + ;; + ((string-match "\\`\\([^@%!]+\\)[@%][^@%!.]+\\'" addr) + (bbdb-match-substring addr 1)) + ;; + ;; Sometimes I see addrs like "foo%somewhere%uunet.uu.net@somewhere.else". + ;; This is silly, because I know that I can send mail to uunet directly. + ;; + ((string-match ".%uunet\\.uu\\.net@[^@%!]+\\'" addr) + (concat (substring addr 0 (+ (match-beginning 0) 1)) "@UUNET.UU.NET")) + ;; + ;; Otherwise, leave it as it is. Returning a string EQ to the one passed + ;; in tells BBDB that we're done. + ;; + (t addr))) + + +;;; Here's another approach; sometimes one gets mail from foo@bar.baz.com, +;;; and then later gets mail from foo@baz.com. At this point, one would +;;; like to delete the bar.baz.com address, since the baz.com address is +;;; obviously superior. See also var `bbdb-canonicalize-redundant-nets-p'. +;;; +;;; Turn this on with +;;; (add-hook 'bbdb-change-hook 'bbdb-delete-redundant-nets) + +(defun bbdb-delete-redundant-nets (record) + "Deletes redundant network addresses. +For use as a value of `bbdb-change-hook'. See `bbdb-net-redundant-p'." + (let* ((nets (bbdb-record-net record)) + (rest nets) + net new redundant) + (while rest + (setq net (car rest)) + (if (bbdb-net-redundant-p net nets) + (setq redundant (cons net redundant)) + (setq new (cons net new))) + (setq rest (cdr rest))) + (cond (redundant + (message "Deleting redundant nets %s..." + (mapconcat 'identity (nreverse redundant) ", ")) + (setq new (nreverse new)) + (bbdb-record-set-net record new) + t)))) + + + +;;;###autoload +(defun bbdb-force-record-create () + "Force automatic creation of a BBDB records for the current message. +You might add this to the reply hook of your MUA in order to automatically +get records added for those people you reply to." + (interactive) + (let ((bbdb/mail-auto-create-p t) + (bbdb/news-auto-create-p t) + (bbdb-message-caching-enabled nil) + (bbdb/gnus-update-records-mode 'annotating) + (bbdb/rmail-update-records-mode 'annotating) + (bbdb/mhe-update-records-mode 'annotating) + (bbdb/vm-update-records-mode 'annotating)) + (save-excursion + (cond ((member major-mode '(vm-mode vm-virtual-mode vm-summary-mode + vm-presentation-mode)) + (bbdb/vm-pop-up-bbdb-buffer)) + ((member major-mode '(gnus-summary-mode gnus-article-mode + gnus-tree-mode)) + (bbdb/gnus-pop-up-bbdb-buffer)) + ((member major-mode '(rmail-mode rmail-summary-mode)) + (bbdb/rmail-pop-up-bbdb-buffer)) + ((member major-mode '(mhe-mode mhe-summary-mode mh-folder-mode)) + (bbdb/mh-pop-up-bbdb-buffer)) + )))) + +(provide 'bbdb-hooks) diff --git a/xemacs-packages/lisp/bbdb/bbdb-hooks.elc b/xemacs-packages/lisp/bbdb/bbdb-hooks.elc new file mode 100644 index 0000000000000000000000000000000000000000..8ffe5621c77b5c25614d950758b435f305d3a6e6 GIT binary patch literal 15930 zcmdU0>vJ2|b+^BXAb~V`jcm*8#mW)@nG2D$9;Vb8fqJW>mqp2sYU$AeSdtq7yU^}J z6w^#Qwq=oUQl}58(_|)-&NMS=2+Ey&$xOewvPJ4GC2899{jGmTf9Kr0z%BtwvYlk6 z@|Xa2@4b8Px##gazjJrb!DIW^KKI;ni9LJvh>}~a*%hlSiZjBwP%u4n!m8vi*@5M_ zdB+Nb>xj2-`(!B)L&IWdaQEQI?(IWjcyMqB4=~}mRWX4f#J0NcZL7E?vx0Ay=WlZ^ zY^zt68lR)q)Vrs5I? zvN4C@q5O7{t(ie-N(}AF3GEN-)uJoLraZe^)5O~cX<%`zUb4%1?p~Y;ELvQ9g#7R> z)ou?>e^4JB(T9d*Yqu8IRr{M}K+m#$tXf_VrtpJThb7^1t>l*RIXz`#9%WZJZXm47 zwjT)F5poVgBl$!kYfp%*>6Asb=+>QbO=RTC)pBx)9+7pu5rh85cIpq9(!65P)6JUl`>PeN{qHY27@zrE`dXd$P~Juz{bRXFET z-SaFb&?~N4*0D`N4o|m&i=yL(aO?`6i~b~counkRPyZ=B_vy{_tR~KR*2TK*S%T)m zf6$~lE{1c7O$BVrnJEhb3@pzvE23-$mcYcSW|05=M7C^ATrxe`37cf;VMATE5!&W= z^vzX$b6FGFO|OW&*tuf_bHTvFuZu%i54KKV(Wa21C{3Bpq{R}+>=9KHrkw80$1Ip#sp-Comj2ooYjNZ6C>v(~b-c4R+lTtQT5C=8ql0vR2xR5;cU0>ZBu?gfv5l zh@`G`Qc7P=r;BW2Bm7q66MMq5%V=n5$B+`zYs2ES71TY}$*SpHusmS~yvU+8X*&+g zU$_%|VG5dp+eP@@3*j{-i3Akahnt1Mogp_iZC5JnupFyIcRaf?BZ_2rG5Hni6BCx# zMRf8}I`-ZRpj5DUp(PjnX2Wnkd9UZ<+>)40-u9c{?rVO~cX95{szQ1;dDm}#eDAY# z^J;JNgI?L>zS;cfftX9B_$N9+5ieDBHCespvVDt5r|#=`l3l7;2q82ldCm1~$iS>D zzX^X~SHhMwVB}}j{D$l4us};>dEiOUt=HrQ{_WSR5cEvsO898%loLEFy=prcmiHrz zC)7O4hkKM7$%E5l=^^-xj+o;MBsU$~mX$N*hVpB?t@6IrDLA+aHdhXbpZ=6PE!3x4 zC|szrv7znTw@dwbZDf}?%r1(|!ZG2D@YK-7WGnUs_~x;C@f%ht&~n&&=!U2Cje1-% zD|PAu9|f(Gj%k^WsLg^)^2qbIG|crbP;j)!QHdG1o*^ISBo3cAJ2oIr(~fYLH;>1A zAm&!cR&j2rH+}omnmczlZs=S1hkN(a3-i^5 zAK&XuH-GTpdU5Xj-9Mc>|Ho_ZJxn+Mtnbl->yPQ@8*AsCpU=$ApXhs)Osr)37AutQ zTc(GY!+O7xF+~ifJuLtp?0__&sLIA|mGznj4?N3a<;{snD+o=~vnC;b{bC)#R%qu$ z&-m8e{8tkJDU+xm3=qJ9fHlL>#2|f83r)~}0HNaoSdc^g@Zj(uX??a-_XD@8m#tF8 z^ehO~v&|wvsf>vBqysI&T>Kz(G;l72XhbH%j%@3wBjg3(yOL)Y$;Zn0qBay!#ua8A zPl3S`I+zjc>MgNv-+_IGBf})nqU(j)&6+sPMgc{pV7kq*rtxHqqRY;D4K`#re2+a= z{2sxvBH})4+!NM9p)+qdXQ0Xo6>)qZHRV;>zTpsd%!(riM-Lo4t)Cb@eh^UU^ufai z-##UBBA?HToZ%3}u`UDcRICBj!_W=^;u{)T8(Ja1)iCl^^D^T5q*-wt{Ibe*LqlH% zokr+cR0qaFQ1?q#1&z>(qfp5tOh$4OaG;(INDbj47F7|=qyf`RT9PL>OBqVdaxpWQ zp5YvC&q18cvs=lMIcI#a)%CW*Wy`iT>^beF3Ac(EO3+MB2jViEF$<$rd_0>#vQiV@ z1jq>@TIJ~3bntw-z5MR;n$`Hs_5t_@URfQ2m)c=gDG@n|K3XuKjLk9kRD|Tr(+H3#* zFVO4BRzxXjXh|_6;!NFiW+>&s+>vL|++pS&mIg(`wf*}kLb}4Tq46Ha+-cH4UY4L` z`77H{7gziLz=n`B4h=;!6teXY4?V$w%UdLxxNpxV+Q@sw(9v>%vE5R!hwPn_#h8QY zB3zM`9efMufshI;b*s!6yFrky0g-Hnvc)aLhPaf9+YZQx0Eofy36!MznpaY(`S(*_ zTU@H$7E6uBOE12#p+C8?|MyDkWX7&R3Bmx`g_5eZ=&}<9qOuE=D#FYpD7XU**#^AvS?vjFq=_%QB zGyp4{+M-%QA#_X(p=-iM-ojKFVJC^i^z9=fJDGObF&Hx;a|OHM1!6+op%2~t3f5Bu z+AUL@G!r120OsU$vF4`)da|8Fv`rUV1H3y*iIE3gB(NIh0%GhWKovPgYN7I{vTONH zCJ<%YzgPzto0vf=roaVlpk#?+!yG?3c4ql7vM&QAID=^akcc9z*H#eFMU+3$@*~@Y zHuzn(rFjFv`fh!43b{>7UQvgaI3E>+|3pp5bjfp8R3YAa#UR`gH-5S(Zrtc;{$%O4 zxYOA9;!7Joy4x$ANpEou$@-o@VP);!=WFpV#nY2TvPafCg7^Z_jPOO;PYjVQG^vvjB zG9080+J0uuq!CNZC3p#%(Dn*#TKd}&ZJ?w{cb>M5ZCYjL(DvbH zNHE#*uwkH&Wx};QtCUNwSb_V4g+ICPIz@7UI>i9Fs|2!vPK>0Yv~d zlvq(7l-|%yr6HX8wJ8myKP?l-SkzYXKeWkAD~AaMhg%>1i-Ai#ft9<1RoW#*)*24n ziDb{^&4?VNlF&d;$VpX>8BI#hjUG5~`rz1@zW>-L{vJCzc4k~Amz2P&gf%b5&YV7a z;&3Z*rQ}mQF^gqjo;5W6QnjGK_M69Ja8@R$G!B|6f($M3!$$}$U9f@(NLLAEc*k#{ zdFrqJp(ky25wr;b71di+7LbS{G`4Obg`D zpesbm8LIz~7)^(RG}$dkCm;1e!|_2Za+QZjLunF3ePN#0wYaJUW~Q`$*!enbfM9z*0=!KxCoGDF<=r=)q$LB+I2d1?9O&eMm|gW)@1*&`@%xx~%eD?KNS7?DDV~RNF;{ zMjTz>cJC{F6C5emuGs^r{@~!)lcV4YHz1>lFpMoUTf;aZz{Z+2=n0oCXyJ8-6%1=b z0IZk@MXX9>QHRhcWH0#{F}60`9eM~UwNxgkj-k2UBz91i|FKe;fU=0f=&5$m(3Cvm zttc#qzHNZLDy@b%PRh`Bla54U!pZp45GBB>YFv~jddAR*EZQQYk>O-d5K&HX#IdkV z0XP`Lpw*G%HiZvY1WFW_P&b2PC)212CFcq#O3$q1IkX_yS)sqmZL(ZW`c5;QWQlysnCi^s`$$ej$Kn+A7VBN z0Z0vBxop-~kVnuynRT1_$t~)0H{nqGtdzn<6y+!aT8#@ zlKH~qy&Q`|kWNaZV*1nQd`0|Exj@gV03eC~QR(W%egYAIo2?o_q$y_wgiBBvfCj+d z1G3mi9N@=@{f`a!CKqr|nYPEHEw3Zs2*-+rgk_5ulZM9oOUVt@V-+vQT4edCJqVPP zF(J8_)6ypsYTzLKC1y~P>kh}`Q#Nc`7)!2QMibe9yd!22-cs&a&1Sz0estTP!FjQY zx_%Pc@A1@^J&a|=OT)vI35FBlV8aWOH)zz*hsrj{86r+o4ueLa*9a#Cr7PkDoH(RB zRJV!n!>Fcx$#(0^+HlNji6C6OMqFrX_44XF5Qqp!E$H9VYNH)SA!P14%DW1$pdc&T zk=%T?U1?rzoEsTOrhbNV(1fE=*iA8I6vo3)kd^qcRfgm!6^-GohK9B*W>PKk-NT?q zrp*~RJmNjL!t(BzTlZjJ1U?y_z;kg(ur8M>b<`Hg?GdD!5$B^r?#{H935L!dE_0ApX%2iFKaNAES*uluw&NMe2(3ak>+}HOE;2}( z7>tGv$tkz201XW~ps)lLBV=J4@aH$_(#WosDg2SA)gzzeN4|{Sku!c4-IG*`EFpJF zjbw>9CAG6m7{1f_ht$MxP(Kf~YvlWmjh-Q8%r7nXvGtR1t{~pO7K2SmR?(b)1=q5kLdNGs#6lD}k^& zh5Us>=5Is4z-PX`s|%m0L$)o33P!|0MP<1i2?14)nPo{R8h{|C@1{2Y+-%O?zn4OuwebG!wS96F%%iV>YUJ+b z$H~I#UnE~&zbQFdSU3OSFIV4Qzv-V-TM&S>^=s55Z(M)elS0*gw9)@+bMAiXRZJYU z%f(!yf1vr(D7mM3^;f+~L!19T6+(N{jsDD@g>R=a&DnqX*JLWQ zX)cw?txF9wf0buTwyNqm8%fXOl}86pfK2lj+}%ERCN-5b9l}Xh+(t8nGc|&Ue-|%1jw5a8t^|oEdCsI zQ4J426MdW}Dk@Q)r+(uCpX)9$2jAm5^iHeazY}{8(0_hy(__|~dr96cn7Q%Te zxcWm{fy-3fTGmtfH^7#%T~@ow?R*?E!Mg)qU7lCwYjm!if)6Icza!pAmQ9vljjU;T zX}x0v*>+qEg@v!7q3yfm=|JLwBM0R9vCDJ>=N=T^S6YMf4vU6!c*H$V3vnV$aue{!eRQ0IBQm(OKFNP-hvsi~~ER$Fy(%uJN%2&5+Vg5%k{MeH3C zdq>3HL3%I1({YecOe!}8BYdUhF3Lulm|L6zql6gG!vt*$lU%|lm%$Fz4Qhoxt zszyJ7JCV!lNm`&G4#j_vuf z^w46@SjR~gdl-ndI7G4~<{;ELSvpAwz9JA(ZqxXXge?$1SO#ECaCvQk5vd3K#4iHD zLlto%6(x7(sKDG3^P%bjOxYM3*;^sjU6DK?iV5KWr`E_R7^CrAkmv9_Nkxl`DugKb zbTsm#Wnc|iXm}Q}lNsQgmAny435hAce-pJGZh_P7MWuG6J0;IW64$mMZUd3uT=iMc zfzNvm9HNM$+Vef47o)%R_9<#PKBS2P_IUjHSP*zDoqa@0h3#)z@bf|IRSpsk<>FTU(G<)-&Y{LWHmII*Y z{jNP9$e#S@*_#jPSEJ`qRbVdVG( zE-t}d@XIhVn!xLL^dr&`cQ$jMJa@`g=*2jsB(TP?lUCpn!cOC_QlIvtxLLLk?+6!! z$8|g^-R^d-uzB1taNJSOEZP)P!3@+&&>-x^PhK`K*4iO!3jEL z;xo~m&UJ@n8q3coh`4|O^I5I-nZff?TO+TWDa^5!(KL=v>2ul@rfwnUl4ujxFh(?yL^b(S0#Y;Z{5T{DRtyCh zPaHoxN=_f|0aC8K?Dc>I6=kv<1{{ zL@Aq<-|V8v$Tr=2ljyiFeTl6t{w|nW6)tueg(pbGnD|L#DG0_njDDpu>9vS0?HJs- XGe^cv01|NJ5{y&5&p=A==Mw)1D=m#| literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-merge.el b/xemacs-packages/lisp/bbdb/bbdb-merge.el new file mode 100644 index 00000000..bfb042bb --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-merge.el @@ -0,0 +1,261 @@ +;;; BBDB merge/sync framework +;;; GNU Public License to go here. This file is under GPL, thanks guys. +;;; Copyright (c) 2000 Waider + +(require 'bbdb) +(require 'bbdb-com) + +;;; to do: +;;; smarter phone, notes and address merging. + +;;;###autoload +(defun bbdb-merge-record (new-record &optional merge-record override) + "Generic merge function. + +Merges new-record into your bbdb, using DATE to check who's more +up-to-date and OVERRIDE to decide who gets precedence if two dates +match. DATE can be extracted from a notes if it's an alist with an +element marked timestamp. Set OVERRIDE to 'new to allow the new record +to stomp on existing data, 'old to preserve existing data or nil to +merge both together. If it can't find a record to merge with, it will +create a new record. If MERGE-RECORD is set, it's a record discovered +by other means that should be merged with. + +Returns the Grand Unified Record." + + (let* ((firstname (bbdb-record-firstname new-record)) + (lastname (bbdb-record-lastname new-record)) + (aka (bbdb-record-aka new-record)) + (nets (bbdb-record-net new-record)) + (addrs (bbdb-record-addresses new-record)) + (phones (bbdb-record-phones new-record)) + (company (bbdb-record-company new-record)) + (notes (bbdb-record-raw-notes new-record)) + (name (bbdb-string-trim (concat firstname " " lastname))) + (date (if (listp notes) (cdr (assq 'timestamp notes)) nil)) + olddate) + + ;; for convenience + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + + ;; See if we have a record that looks right, using an intertwingle + ;; search. Could probably parameterize that. + ;; bbdb-merge-search-function or some such. + (if (null merge-record) + (setq merge-record (bbdb-search-simple name nets))) + + (if merge-record + (progn + ;; if date is unset, set it to the existing record's date. + (setq olddate (bbdb-record-getprop merge-record 'timestamp) + date (or date olddate)) + ;; FIXME if date & olddate are STILL unset, set to today's date. + + ;; if the old record is actually newer, invert the sense of override + (if (string-lessp olddate date) + (setq override (cond ((eq 'old override) 'new) + ((eq 'new override) 'old) + (t nil)))) + + (bbdb-record-set-firstname merge-record + (if (null override) + (bbdb-merge-strings (bbdb-record-firstname merge-record) + firstname " ") + (if (eq 'new override) firstname + (bbdb-record-firstname merge-record)))) + + (bbdb-record-set-lastname merge-record + (if (null override) + (bbdb-merge-strings (bbdb-record-lastname merge-record) + lastname " ") + (if (eq 'new override) lastname + (bbdb-record-lastname merge-record)))) + + (bbdb-record-set-company merge-record + (if (null override) + (bbdb-merge-strings (bbdb-record-company merge-record) + company " ") + (if (eq 'new override) company + (bbdb-record-company merge-record)))) + + (bbdb-record-set-aka + merge-record + (if (null override) + (bbdb-merge-lists! + (bbdb-record-aka merge-record) + (if (listp aka) aka (list aka)) 'string= 'downcase) + (if (eq 'new override) aka + (bbdb-record-aka merge-record)))) + + (bbdb-record-set-net + merge-record + (if (null override) + (bbdb-merge-lists! + (bbdb-record-net merge-record) nets 'string= 'downcase) + (if (eq 'new override) nets + (bbdb-record-net merge-record)))) + + (bbdb-record-set-phones + merge-record + (if (null override) + (bbdb-merge-lists! + (bbdb-record-phones merge-record) phones 'equal) + (if (eq 'new override) phones + (bbdb-record-phones merge-record)))) + + (bbdb-record-set-addresses + merge-record + (if (null override) + (bbdb-merge-lists! + (bbdb-record-addresses merge-record) addrs 'equal) + (if (eq 'new override) addrs + (bbdb-record-addresses merge-record)))) + + ;; lifted from bbdb-com.el + (let ((n1 (bbdb-record-raw-notes merge-record)) + (n2 notes) + tmp + (bbdb-refile-notes-default-merge-function ;; XXX + 'bbdb-merge-strings)) + (or (equal n1 n2) + (progn + (or (listp n1) (setq n1 (list (cons 'notes n1)))) + (or (listp n2) (setq n2 (list (cons 'notes n2)))) + (while n2 + (if (setq tmp (assq (car (car n2)) n1)) + (setcdr tmp + (funcall (or (cdr (assq (car (car n2)) + bbdb-refile-notes-generate-alist)) + bbdb-refile-notes-default-merge-function) + (cdr tmp) (cdr (car n2)))) + (setq n1 (nconc n1 (list (car n2))))) + (setq n2 (cdr n2))) + (bbdb-record-set-raw-notes merge-record n1))))) + + ;; we couldn't find a record, so create one + (setq merge-record + (bbdb-create-internal name company nets addrs phones notes)) + ;; bite me, bbdb-create-internal + (bbdb-record-set-firstname merge-record firstname) + (bbdb-record-set-lastname merge-record lastname)) + + ;; more general bitingness + (if (equal (bbdb-record-firstname merge-record) "") + (bbdb-record-set-firstname merge-record nil)) + (if (equal (bbdb-record-lastname merge-record) "") + (bbdb-record-set-lastname merge-record nil)) + + ;; fix up the in-memory copy. + (bbdb-change-record merge-record t) + (let ((name (bbdb-record-name merge-record)) + (company (bbdb-record-company merge-record))) + (if (> (length name) 0) + (bbdb-remhash (downcase name) merge-record)) + (if (> (length company) 0) + (bbdb-remhash (downcase company) merge-record))) + (bbdb-record-set-namecache merge-record nil) + (if (or (bbdb-record-lastname merge-record) + (bbdb-record-firstname merge-record)) + (bbdb-puthash (downcase (bbdb-record-name merge-record)) merge-record)) + (if (bbdb-record-company merge-record) + (bbdb-puthash (downcase (bbdb-record-company merge-record)) + merge-record)) + (bbdb-with-db-buffer + (if (not (memq merge-record bbdb-changed-records)) + (setq bbdb-changed-records + (cons merge-record bbdb-changed-records)))) + + ;; your record, sir. + merge-record)) + +;; fixme these could be a macros, I guess. +(defun bbdb-instring( s1 s2 ) +;; (and case-fold-search +;; (setq s1 (downcase s1) +;; s2 (downcase s2))) + (catch 'done + (while (>= (length s1) (length s2)) + (if (string= s2 (substring s1 0 (length s2))) + (throw 'done t) + (setq s1 (substring s1 1)))) + (throw 'done nil))) + +(defun bbdb-merge-strings (s1 s2 &optional sep) + "Merge two strings together uniquely. +If s1 doesn't contain s2, return s1+sep+s2." + (cond ((or (null s1) (string-equal s1 "")) s2) + ((or (null s2) (string-equal s2 "")) s1) + (t (if (bbdb-instring s2 s1) s1 + (concat s1 (or sep "") s2))))) + +;;;###autoload +(defun bbdb-merge-file (&optional bbdb-new override match-fun) + "Merge a bbdb file into the in-core bbdb." + (interactive "fMerge bbdb file: ") + (or bbdb-gag-messages + bbdb-silent-running + (message "Merging %s" bbdb-new)) + ;; argh urgle private environment + (let* ((bbdb-live-file bbdb-file) + (bbdb-file bbdb-new) + (bbdb-live-buffer-name bbdb-buffer-name) + (bbdb-buffer-name "*BBDB-merge*") + (bbdb-buffer nil) ;; hack hack + (new-records (bbdb-records)) + (bbdb-buffer nil) ;; hack hack + (bbdb-file bbdb-live-file) + (bbdb-buffer-name bbdb-live-buffer-name) + (bbdb-refile-notes-default-merge-function 'bbdb-merge-strings)) + + ;; merge everything + (mapcar (lambda(rec) + (bbdb-merge-record rec + (and match-fun + (funcall match-fun rec)) + override)) + new-records)) + ;; hack + (setq bbdb-buffer (or (get-file-buffer bbdb-file) nil))) + +(defun bbdb-add-or-update-phone ( record location phone-string ) + "Add or update a phone number in the current record. + +Insert into RECORD phone number for LOCATION consisting of +PHONE-STRING. Will automatically overwrite an existing phone entry for +the same location." + (let* ((phone (make-vector (if bbdb-north-american-phone-numbers-p + bbdb-phone-length + 2) + nil))) + (if (= 2 (length phone)) + (aset phone 1 phone-string) + (let ((newp (bbdb-parse-phone-number phone-string))) + (bbdb-phone-set-area phone (nth 0 newp)) + (bbdb-phone-set-exchange phone (nth 1 newp)) + (bbdb-phone-set-suffix phone (nth 2 newp)) + (bbdb-phone-set-extension phone (or (nth 3 newp) 0)))) + (bbdb-phone-set-location phone location) + + ;; "phone" now contains a suitable record + ;; we need to check if this is already in the phones list + (let ((phones (bbdb-record-phones record)) + phones-list) + (setq phones-list phones) + (while (car phones-list) + (if (string= (bbdb-phone-location (car phones-list)) + location) + (setq phones (delete (car phones-list) phones))) + (setq phones-list (cdr phones-list))) + + + (bbdb-record-set-phones record + (nconc phones (list phone)))) + (bbdb-change-record record nil) + + ;; update display if record is visible + (and (get-buffer-window bbdb-buffer-name) + (bbdb-display-records (list record))) + nil)) + +(provide 'bbdb-merge) diff --git a/xemacs-packages/lisp/bbdb/bbdb-merge.elc b/xemacs-packages/lisp/bbdb/bbdb-merge.elc new file mode 100644 index 0000000000000000000000000000000000000000..505ef80bd9730c4b4d9837a6b431d5878bbe7897 GIT binary patch literal 5424 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 Bcb@ +;;; Interface to mh-e version 3.7 or later (modeled after bbdb-rmail). +;;; Created 5-Mar-91; +;;; Modified: 28-Jul-94 by Fritz Knabe +;;; Jack Repenning + +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-mhe.el,v 1.5 2005/07/24 15:22:57 waider Exp $ +;; + +(eval-and-compile + (require 'bbdb) + (require 'bbdb-com) + (require 'mail-utils) + ;; We advise several mh-e functions + (require 'mh-e) + (if (fboundp 'mh-version) + (require 'mh-comp)) ; For mh-e 4.x + (require 'advice)) + +(defmacro bbdb/mh-cache-key (message) + "Return a (numeric) key for MESSAGE" + (`(let* ((attrs (file-attributes (, message))) + (status-time (nth 6 attrs)) + (status-time-2 (cdr status-time)) + (inode (nth 10 attrs))) + (logxor (if (integerp inode) ;; if inode is larger than an emacs int, + inode ;; it's returned as a dotted pair + (car inode)) + (car status-time) + ;; We need the following test because XEmacs returns the + ;; status time as a dotted pair, whereas FSF and Epoch + ;; return it as list. + (if (integerp status-time-2) + status-time-2 + (car status-time-2)))))) + +;;;###autoload +(defun bbdb/mh-update-record (&optional offer-to-create) + "Returns the record corresponding to the current MH message, creating or +modifying it as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." + (save-excursion + (and mh-show-buffer (set-buffer mh-show-buffer)) + (if bbdb-use-pop-up + (bbdb/mh-pop-up-bbdb-buffer offer-to-create) + (let ((msg (bbdb/mh-cache-key buffer-file-name)) + records record) + (if (eq msg 0) (setq msg nil)) ; 0 could mean trouble; be safe. + (setq records (bbdb-message-cache-lookup msg)) + (if records + (car records) + (let ((from (bbdb/mh-get-field "^From[ \t]*:"))) + (if (or (string= "" from) + (string-match (bbdb-user-mail-names) + (mail-strip-quoted-names from))) + ;; if logged-in user sent this, use recipients. + (progn + (setq from (bbdb/mh-get-field "^To[ \t]*:")) + (if (or (string= "" from) + (string-match (bbdb-user-mail-names) + (mail-strip-quoted-names from))) + (setq from nil)))) + (if from + (setq record + (bbdb-annotate-message-sender + from t + (or (bbdb-invoke-hook-for-value bbdb/mail-auto-create-p) + offer-to-create) + offer-to-create))) + (if (and msg record) (bbdb-encache-message msg (list record))) + ;; return one record + record)))))) + +;;;###autoload +(defun bbdb/mh-annotate-sender (string &optional replace) + "Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." + (interactive (list (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.") + (read-string "Comments: ")))) + (mh-show) + (let ((b (current-buffer)) + (p (point))) + (set-buffer mh-show-buffer) + (bbdb-annotate-notes (bbdb/mh-update-record t) string 'notes replace) + (set-buffer b) + (goto-char p))) + + +(defun bbdb/mh-edit-notes (&optional arg) + "Edit the notes field or (with a prefix arg) a user-defined field +of the BBDB record corresponding to the sender of this message." + (interactive "P") + (mh-show) + (let ((b (current-buffer)) + (p (point))) + (set-buffer mh-show-buffer) + (let (bbdb-electric-p (record (or (bbdb/mh-update-record t) (error "")))) + (bbdb-display-records (list record)) + (if arg + (bbdb-record-edit-property record nil t) + (bbdb-record-edit-notes record t))) + (set-buffer b) + (goto-char p))) + + +;;;###autoload +(defun bbdb/mh-show-sender () + "Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." + (interactive) + (mh-show) + (let ((b (current-buffer)) + (p (point))) + (set-buffer mh-show-buffer) + (let ((record (bbdb/mh-update-record t))) + (if record + (bbdb-display-records (list record)) + (error "unperson"))) + (set-buffer b) + (goto-char p))) + + +(defun bbdb/mh-pop-up-bbdb-buffer (&optional offer-to-create) + "Make the *BBDB* buffer be displayed along with the MH window, +displaying the record corresponding to the sender of the current message." + (bbdb-pop-up-bbdb-buffer + (function (lambda (w) + (let ((b (current-buffer))) + (set-buffer (window-buffer w)) + (prog1 (eq major-mode 'mh-folder-mode) + (set-buffer b)))))) + (let ((bbdb-gag-messages t) + (bbdb-use-pop-up nil) + (bbdb-electric-p nil)) + (let ((record (bbdb/mh-update-record offer-to-create))) + (bbdb-display-records (if record (list record) nil) + bbdb-pop-up-display-layout) + record))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; this is a more strict version of mh-get-field which takes an regexp + +(defun bbdb/mh-get-field (field) + ;; Find and return the value of field FIELD (regexp) in the current buffer. + ;; Returns the empty string if the field is not in the message. + (let ((case-fold-search nil)) + (goto-char (point-min)) + (cond ((not (re-search-forward field nil t)) "") + ((looking-at "[\t ]*$") "") + (t (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t) + (let ((field (buffer-substring (match-beginning 1) (match-end 1))) + (end-of-match (point))) + (forward-line) + (while (looking-at "[ \t]") (forward-line 1)) + (backward-char 1) + (if (<= (point) end-of-match) + field + (format "%s%s" field + (buffer-substring end-of-match (point))))))))) + +(defadvice mh-process-commands (after mh-bbdb-process act) + (bbdb-offer-save)) + +(defadvice mh-send (before mh-bbdb-send act) + (interactive (list + (bbdb-read-addresses-with-completion "To: ") + (bbdb-read-addresses-with-completion "Cc: ") + (read-string "Subject: ")))) + +(defadvice mh-send-other-window (before mh-bbdb-send-other act) + (interactive (list + (bbdb-read-addresses-with-completion "To: ") + (bbdb-read-addresses-with-completion "Cc: ") + (read-string "Subject: ")))) + +(defadvice mh-forward (before mh-bbdb-forward act) + (interactive (list (bbdb-read-addresses-with-completion "To: ") + (bbdb-read-addresses-with-completion "Cc: ") + (if current-prefix-arg + (mh-read-seq-default "Forward" t) + (mh-get-msg-num t))))) + +(defadvice mh-redistribute (before mh-bbdb-redist act) + (interactive (list + (bbdb-read-addresses-with-completion "Redist-To: ") + (bbdb-read-addresses-with-completion "Redist-Cc: ") + (mh-get-msg-num t)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; mail from bbdb-mode using mh + +;; these redefine the bbdb-send-mail functions to use mh-send. + +;;; Install bbdb into mh-e's show-message function + +;;;###autoload +(defun bbdb-insinuate-mh () + "Call this function to hook BBDB into MH-E." + (define-key mh-folder-mode-map ":" 'bbdb/mh-show-sender) + (define-key mh-folder-mode-map ";" 'bbdb/mh-edit-notes) + (define-key mh-letter-mode-map "\M-;" 'bbdb-complete-name) + (add-hook 'mh-show-hook 'bbdb/mh-update-record) + (define-key mh-letter-mode-map "\e\t" 'bbdb-complete-name)) + +(provide 'bbdb-mhe) diff --git a/xemacs-packages/lisp/bbdb/bbdb-mhe.elc b/xemacs-packages/lisp/bbdb/bbdb-mhe.elc new file mode 100644 index 0000000000000000000000000000000000000000..e539addb664bd4031233865716636b9c34660570 GIT binary patch literal 5450 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 NY{^$g{6?*i{SVpOW*h(j literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-migrate.el b/xemacs-packages/lisp/bbdb/bbdb-migrate.el new file mode 100644 index 00000000..745c7015 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-migrate.el @@ -0,0 +1,486 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file contains the migration functions for the Insidious Big +;;; Brother Database (aka BBDB), copyright (c) 1991, 1992, 1993, 1994 +;;; Jamie Zawinski . See the file bbdb.texinfo for +;;; documentation. +;;; +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;;; + +;; +;; $Id: bbdb-migrate.el,v 1.8 2005/07/24 15:22:58 waider Exp $ +;; +;; $Log: bbdb-migrate.el,v $ +;; Revision 1.8 2005/07/24 15:22:58 waider +;; sync with Sourceforge CVS +;; +;; Revision 1.20 2004/03/22 15:55:03 waider +;; * Minor docstring fix (Stefan Monnier) +;; * Catch error if attempting to kill only window in frame (Stefan Monnier) +;; +;; Revision 1.19 2002/08/19 22:49:12 waider +;; Jim Blandy's fix for migrating notes. +;; +;; Revision 1.18 2002/05/12 22:17:03 waider +;; Dave Love's big patch. See ChangeLog for full details. +;; +;; Revision 1.17 2001/05/17 17:15:31 fenk +;; (bbdb-unmigrate-zip-codes-to-strings): Fixed the faulty use of let instead of let*. +;; +;; Revision 1.16 2000/11/27 12:59:53 waider +;; Alex's zipcode changes. WARNING: New database format. +;; +;; Revision 1.15 2000/08/05 15:38:04 waider +;; When converting the streets to a list, delete "nil" as well as "". +;; +;; Revision 1.14 2000/07/11 21:28:44 sds +;; (bbdb-migrate-record-lambda): `mapcar', not `mapc' here! +;; +;; Revision 1.13 2000/07/10 17:00:12 sds +;; revert the last patch (`mapc' is more efficient than `mapcar') +;; +;; Revision 1.12 2000/07/09 09:20:11 waider +;; GNUmacs doesn't have "mapc". +;; +;; Revision 1.11 2000/07/05 21:43:35 sds +;; rewrote migration in a modular way +;; +;; Revision 1.10 2000/06/30 19:12:36 sds +;; (bbdb-migrate): re-wrote using `mapcar' instead of `append' +;; this is linear instead of quadratic and avoids much consing +;; +;; Revision 1.9 2000/05/29 22:47:50 waider +;; *** empty log message *** +;; +;; Revision 1.8 2000/04/17 08:30:47 waider +;; omitted bracket on unmigrate for v5->v4 +;; +;; Revision 1.7 2000/04/16 04:00:54 waider +;; * Added 5->4 unmigration +;; +;; Revision 1.6 2000/04/15 14:57:38 waider +;; * Fixed misplaced bracket in street migration code. +;; +;; Revision 1.5 2000/04/12 23:57:16 waider +;; * Added v5 migration. NB no back-migration yet. +;; +;; Revision 1.4 2000/04/05 16:45:07 bbdb-writer +;; * Added Alex's BBDB v4 format migration (country field) +;; +;; Revision 1.3 1998/10/10 18:47:21 simmonmt +;; From slbaur: Don't pass an integer to concat. +;; Format dates with number format - not string - so we get leading +;; zeros. +;; +;; Revision 1.2 1998/04/11 07:19:19 simmonmt +;; Colin Rafferty's patch adding autoload cookies back +;; +;; Revision 1.1 1998/01/06 06:06:06 simmonmt +;; Initial revision +;; +;; + +(require 'bbdb) + +;;; Migrating the BBDB + +;; Features that have changed in the various database revs. Format: +;; ((VERSION . DIFFERENCES) ... ) +(defconst bbdb-migration-features + '((3 . "* Date format for `creation-date' and `timestamp' has changed, + from \"dd mmm yy\" (ex: 25 Sep 97) to \"yyyy-mm-dd\" (ex: 1997-09-25).") + (4 . "* Country field added.") + (5 . "* More flexible street address.") + (6 . "* Zip codes are stored as plain strings."))) + +;;;###autoload +(defun bbdb-migration-query (ondisk) + "Ask if the database is to be migrated. +ONDISK is the version number of the database as currently stored on +disk. Returns the version for the saved database." + (save-excursion + (let ((wc (current-window-configuration)) + (buf (get-buffer-create "*BBDB Migration Info*")) + (newfeatures bbdb-migration-features) + (first t) + win update) + (set-buffer buf) + (erase-buffer) + (goto-char (point-min)) + (insert-string (format "BBDB new data version notice: +============================= + +Your BBDB data is stored in an older format (version %d). At this point, +you have the option of either upgrading or continuing to save your data +in your current format. Please note that if you elect the latter option, +any changes made to your data using features intended for the newer +versions will be lost. For your convenience, a list of file format +changes introduced after version %d is shown below:\n\n" ondisk ondisk)) + (while newfeatures + (if (> (caar newfeatures) ondisk) + (insert-string (concat (if first (setq first nil) "\n\n") + "New features in database version " + (format "%d" (caar newfeatures)) + ":\n\n" (cdar newfeatures)))) + (setq newfeatures (cdr newfeatures))) + (setq win (display-buffer buf)) + (shrink-window-if-larger-than-buffer win) + (setq update + (y-or-n-p (concat "Upgrade BBDB to version " + (format "%d" bbdb-file-format) + "? "))) + (condition-case nil + (delete-window win) + ;; The window might be the only one on its frame. Hopefully, it's + ;; a dedicated window and the kill-buffer below will DTRT. + (error nil)) + (kill-buffer buf) + (set-window-configuration wc) + (if update bbdb-file-format ondisk)))) + +;;;###autoload +(defun bbdb-migrate (records) + "Migrate the BBDB from the version on disk (the car of +`bbdb-file-format-migration') to the current version (in +`bbdb-file-format')." + (bbdb-mapc (bbdb-migrate-versions-lambda (car bbdb-file-format-migration)) + records) + records) + +;;;###autoload +(defun bbdb-unmigrate-record (record) + "Reverse-migrate a single record from the current version (in +`bbdb-file-format') to the version to be saved (the cdr of +`bbdb-file-format-migration')." + (funcall (bbdb-migrate-versions-lambda bbdb-file-format + (car bbdb-file-format-migration)) + record) + record) + +(defconst bbdb-migration-spec + '((2 (bbdb-record-raw-notes bbdb-record-set-raw-notes + bbdb-migrate-change-dates)) + (3 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-migrate-add-country-field)) + (4 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-migrate-streets-to-list)) + (5 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-migrate-zip-codes-to-strings))) + "The alist of (version . migration-spec-list). +See `bbdb-migrate-record-lambda' for details.") + +(defconst bbdb-unmigration-spec + '((2 (bbdb-record-raw-notes bbdb-record-set-raw-notes + bbdb-unmigrate-change-dates)) + (3 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-unmigrate-add-country-field)) + (4 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-unmigrate-streets-to-list)) + (5 (bbdb-record-addresses bbdb-record-set-addresses + bbdb-unmigrate-zip-codes-to-strings))) + "The alist of (version . migration-spec-list). +See `bbdb-migrate-record-lambda' for details.") + +(defun bbdb-migrate-record-lambda (changes) + "Return a function which will migrate a single record. +CHANGES is a `migration-spec-list' containing entries of the form + + (GET SET FUNCTION) + +where GET is the function to be used to retrieve the field to be +modified, and SET is the function to be used to set the field to be +modified. FUNCTION will be applied to the result of GET, and its +results will be saved with SET." + (byte-compile `(lambda (rec) + ,@(mapcar (lambda (ch) + `(,(cadr ch) rec + (,(car (cddr ch)) + (,(car ch) rec)))) + changes) + rec))) + +(defun bbdb-migrate-versions-lambda (v0 &optional v1) + "Return the function to migrate from V0 to V1. +V1 defaults to `bbdb-file-format'." + (setq v1 (or v1 bbdb-file-format)) + (let ((vv v0) spec) + (while (/= vv v1) + (setq spec (append spec (cdr (assoc vv bbdb-migration-spec))) + vv (if (< v0 v1) (1+ vv) (1- vv)))) + (bbdb-migrate-record-lambda spec))) + +(defun bbdb-migrate-zip-codes-to-strings (addrs) + "Make all zip codes plain strings. +This uses the code that used to be in bbdb-address-zip-string." + ;; apply the function to all addresses in the list and return a + ;; modified list of addresses + (mapcar (lambda (addr) + (let ((zip (if (stringp (bbdb-address-zip addr)) + (bbdb-address-zip addr) + ;; if not a string, make it a string... + (if (consp (bbdb-address-zip addr)) + ;; if a cons cell with two strings + (if (and (stringp (car (bbdb-address-zip addr))) + (stringp (car (cdr (bbdb-address-zip addr))))) + ;; if the second string starts with 4 digits + (if (string-match "^[0-9][0-9][0-9][0-9]" + (car (cdr (bbdb-address-zip addr)))) + (concat (car (bbdb-address-zip addr)) + "-" + (car (cdr (bbdb-address-zip addr)))) + ;; if ("abc" "efg") + (concat (car (bbdb-address-zip addr)) + " " + (car (cdr (bbdb-address-zip addr))))) + ;; if ("SE" (123 45)) + (if (and (stringp (nth 0 (bbdb-address-zip addr))) + (consp (nth 1 (bbdb-address-zip addr))) + (integerp (nth 0 (nth 1 (bbdb-address-zip addr)))) + (integerp (nth 1 (nth 1 (bbdb-address-zip addr))))) + (format "%s-%d %d" + (nth 0 (bbdb-address-zip addr)) + (nth 0 (nth 1 (bbdb-address-zip addr))) + (nth 1 (nth 1 (bbdb-address-zip addr)))) + ;; if a cons cell with two numbers + (if (and (integerp (car (bbdb-address-zip addr))) + (integerp (car (cdr (bbdb-address-zip addr))))) + (format "%05d-%04d" (car (bbdb-address-zip addr)) + (car (cdr (bbdb-address-zip addr)))) + ;; else a cons cell with a string an a number (possible error + ;; if a cons cell with a number and a string -- note the + ;; order!) + (format "%s-%d" (car (bbdb-address-zip addr)) + (car (cdr (bbdb-address-zip addr))))))) + ;; if nil or zero + (if (or (eq 0 (bbdb-address-zip addr)) + (null (bbdb-address-zip addr))) + "" + ;; else a number, could be 3 to 5 digits (possible error: assuming + ;; no leading zeroes in zip codes) + (format "%d" (bbdb-address-zip addr))))))) + (bbdb-address-set-zip addr zip)) + addr) + addrs)) + +(defun bbdb-unmigrate-zip-codes-to-strings (addrs) + "Make zip code string into zip code datastructures. +This uses the code that used to be in bbdb-parse-zip-string." + ;; apply the function to all addresses in the list and return a + ;; modified list of addresses + (mapcar (lambda (addr) + (let* ((string (bbdb-address-zip addr)) + (zip (cond ((string-match "^[ \t\n]*$" string) 0) + ;; Matches 1 to 6 digits. + ((string-match "^[ \t\n]*[0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[ \t\n]*$" string) + (string-to-int string)) + ;; Matches 5 digits and 3 or 4 digits. + ((string-match "^[ \t\n]*\\([0-9][0-9][0-9][0-9][0-9]\\)[ \t\n]*-?[ \t\n]*\\([0-9][0-9][0-9][0-9]?\\)[ \t\n]*$" string) + (list (bbdb-subint string 1) (bbdb-subint string 2))) + ;; Match zip codes for Canada, UK, etc. (result is ("LL47" "U4B")). + ((string-match + "^[ \t\n]*\\([A-Za-z0-9]+\\)[ \t\n]+\\([A-Za-z0-9]+\\)[ \t\n]*$" + string) + (list (substring string (match-beginning 1) (match-end 1)) + (substring string (match-beginning 2) (match-end 2)))) + ;; Match zip codes for continental Europe. Examples "CH-8057" + ;; or "F - 83320" (result is ("CH" "8057") or ("F" "83320")). + ;; Support for "NL-2300RA" added at request from Carsten Dominik + ;; + ((string-match + "^[ \t\n]*\\([A-Z]+\\)[ \t\n]*-?[ \t\n]*\\([0-9]+ ?[A-Z]*\\)[ \t\n]*$" string) + (list (substring string (match-beginning 1) (match-end 1)) + (substring string (match-beginning 2) (match-end 2)))) + ;; Match zip codes from Sweden where the five digits are grouped 3+2 + ;; at the request from Mats Lofdahl . + ;; (result is ("SE" (133 36))) + ((string-match + "^[ \t\n]*\\([A-Z]+\\)[ \t\n]*-?[ \t\n]*\\([0-9]+\\)[ \t\n]+\\([0-9]+\\)[ \t\n]*$" string) + (list (substring string (match-beginning 1) (match-end 1)) + (list (bbdb-subint string 2) + (bbdb-subint string 3))))))) + (bbdb-address-set-zip addr zip) + addr)) + addrs)) + +(defun bbdb-migrate-change-dates (rec) + "Change date formats. +Formats are changed in timestamp and creation-date fields from +\"dd mmm yy\" to \"yyyy-mm-dd\". Assumes the notes are passed in as an +argument." + (unless (stringp rec) + (bbdb-mapc (lambda (rr) + (when (memq (car rr) '(creation-date timestamp)) + (bbdb-migrate-change-dates-change-field rr))) + rec) + rec)) + +(defun bbdb-migrate-change-dates-change-field (field) + "Migrate the date field (the cdr of FIELD) from \"dd mmm yy\" to +\"yyyy-mm-dd\"." + (let ((date (cdr field)) + parsed) + ;; Verify and extract - this is fairly hideous + (and (equal (setq parsed (timezone-parse-date (concat date " 00:00:00"))) + ["0" "0" "0" "0" nil]) + (equal (setq parsed (timezone-parse-date date)) + ["0" "0" "0" "0" nil]) + (cond ((string-match + "^\\([0-9]\\{4\\}\\)[-/]\\([ 0-9]?[0-9]\\)[-/]\\([ 0-9]?[0-9]\\)" date) + (setq parsed (vector (string-to-int (match-string 1 date)) + (string-to-int (match-string 2 date)) + (string-to-int (match-string 3 date)))) + ;; This should be fairly loud for GNU Emacs users + (bbdb-warn "BBDB is treating %s field value %s as %s %d %d" + (car field) (cdr field) + (upcase-initials + (downcase (car (rassoc (aref parsed 1) + timezone-months-assoc)))) + (aref parsed 2) (aref parsed 0))) + ((string-match + "^\\([ 0-9]?[0-9]\\)[-/]\\([ 0-9]?[0-9]\\)[-/]\\([0-9]\\{4\\}\\)" date) + (setq parsed (vector (string-to-int (match-string 3 date)) + (string-to-int (match-string 1 date)) + (string-to-int (match-string 2 date)))) + ;; This should be fairly loud for GNU Emacs users + (bbdb-warn "BBDB is treating %s field value %s as %s %d %d" + (car field) (cdr field) + (upcase-initials + (downcase (car (rassoc (aref parsed 1) + timezone-months-assoc)))) + (aref parsed 2) (aref parsed 0))) + (t ["0" "0" "0" "0" nil]))) + + ;; I like numbers + (and (stringp (aref parsed 0)) + (aset parsed 0 (string-to-int (aref parsed 0)))) + (and (stringp (aref parsed 1)) + (aset parsed 1 (string-to-int (aref parsed 1)))) + (and (stringp (aref parsed 2)) + (aset parsed 2 (string-to-int (aref parsed 2)))) + + ;; Sanity check + (cond ((and (< 0 (aref parsed 0)) + (< 0 (aref parsed 1)) (>= 12 (aref parsed 1)) + (< 0 (aref parsed 2)) + (>= (timezone-last-day-of-month (aref parsed 1) + (aref parsed 0)) + (aref parsed 2))) + (setcdr field (format "%04d-%02d-%02d" (aref parsed 0) + (aref parsed 1) (aref parsed 2))) + field) + (t + (error "BBDB cannot parse %s header value %S for upgrade" + field date))))) + +(defun bbdb-unmigrate-change-dates (rec) + "Change date formats. +Formats are changed in timestamp and creation-date fields from +\"yyyy-mm-dd\" to \"dd mmm yy\". Assumes the notes list is passed in +as an argument." + (unless (stringp rec) + (bbdb-mapc (lambda (rr) + (when (memq (car rr) '(creation-date timestamp)) + (bbdb-unmigrate-change-dates-change-field rr))) + rec) + rec)) + +(defun bbdb-unmigrate-change-dates-change-field (field) + "Unmigrate the date field (the cdr of FIELD) from \"yyyy-mm-dd\" to +\"yyyy-mm-dd\"." + (cons (car field) (bbdb-time-convert (cdr field) "%e %b %y"))) + +(defun bbdb-migrate-add-country-field (addrl) + "Add a country field to each address in the address list." + (mapcar (lambda (addr) (vconcat addr [""])) addrl)) + +(defun bbdb-unmigrate-add-country-field (addrl) + "Remove the country field from each address in the address list." + ;; Some version 4 zip codes will be illegal version 3 (as used in + ;; 2.00.06) zip codes. This problem has not been solved. + (mapcar (lambda (addr) + (let* ((len (1- (length addr))) + (new-addr (make-vector len nil)) + (ii 0)) + (while (< ii len) + (aset new-addr ii (aref addr ii)) + (setq ii (1+ ii))))) + addrl)) + +(defun bbdb-migrate-streets-to-list (addrl) + "Convert the streets to a list." + (mapcar (lambda (addr) + (vector (aref addr 0) ; tag + (delete nil (delete "" ; nuke empties + (list (aref addr 1) ; street1 + (aref addr 2) ; street2 + (aref addr 3))));street3 + (aref addr 4) ; city + (aref addr 5) ; state + (aref addr 6) ; zip + (aref addr 7))) ; country + addrl)) + +(defun bbdb-unmigrate-streets-to-list (addrl) + "Convert the street list to the street[1-3] format." + ;; Take all the old addresses, ie. the 5th field, and for each + ;; address, render the third element (a list of streets) as three + ;; vector elements (v4-style address). If there's more than 3 + ;; lines, everything remaining gets crammed into the third, using + ;; commas to separate the bits. If there's less, fill out with nil. + (mapcar (lambda (addr) + (let ((streets (aref addr 1))) + (vector (aref addr 0) ; tag + (or (nth 0 streets) "") + (or (nth 1 streets) "") + (mapconcat 'identity (cddr streets) ", ") + (aref addr 2) ; city + (aref addr 3) ; state + (aref addr 4) ; zip + (aref addr 5)))) ; country + addrl)) + +;;;###autoload +(defun bbdb-migrate-rewrite-all (message-p &optional records) + "Rewrite each and every record in the bbdb file; this is necessary if we +are updating an old file format. MESSAGE-P says whether to sound off +for each record converted. If RECORDS is non-nil, its value will be +used as the list of records to update." + ;; RECORDS is used by the migration mechanism. Since the migration + ;; mechanism is called from within bbdb-records, if we called + ;; bbdb-change-record, we'd recurse and die. We're therefore left + ;; with the slightly more palatable (but still not pretty) calling + ;; of bbdb-overwrite-record-internal. + (or records (setq records (bbdb-records))) + (let ((i 0)) + (while records + (bbdb-overwrite-record-internal (car records) nil) + (if message-p (message "Updating %d: %s %s" (setq i (1+ i)) + (bbdb-record-firstname (car records)) + (bbdb-record-lastname (car records)))) + (setq records (cdr records))))) +(defalias 'bbdb-dry-heaves 'bbdb-migrate-rewrite-all) + +;;;###autoload +(defun bbdb-migrate-update-file-version (old new) + "Change the `file-version' string from the OLD version to the NEW +version." + (goto-char (point-min)) + (if (re-search-forward (format "^;;; file-version: %d$" old) nil t) + (replace-match (format ";;; file-version: %d" new)) + (error (format "Can't find file-version string in %s buffer for v%d migration" + bbdb-file new)))) + +(provide 'bbdb-migrate) diff --git a/xemacs-packages/lisp/bbdb/bbdb-migrate.elc b/xemacs-packages/lisp/bbdb/bbdb-migrate.elc new file mode 100644 index 0000000000000000000000000000000000000000..da06b8281e976dfa1b10c48b2c09a9db38d0f1df GIT binary patch literal 9727 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 EUy3%}xBvhE literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-print.el b/xemacs-packages/lisp/bbdb/bbdb-print.el new file mode 100644 index 00000000..ffc6ff95 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-print.el @@ -0,0 +1,734 @@ +;;; bbdb-print.el -- for printing BBDB databases using TeX. + +;;; Authors: Boris Goldowsky +;;; Dirk Grunwald +;;; Luigi Semenzato +;;; Copyright (C) 1993 Boris Goldowsky +;;; Version: 3.92; 4Jan95 + +;;; This file is part of the bbdb-print extensions to the Insidious +;;; Big Brother Database, which is for use with GNU Emacs. +;;; +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: +;;; +;;; In the *BBDB* buffer, type P to convert the listing to TeX +;;; format. It will prompt you for a filename. Then run TeX on that +;;; file and print it out. +;;; +;;; Bbdb-print understands one new bbdb field: tex-name. If it +;;; exists, this will be used for the printed listing instead of the +;;; name field of that record. This is designed for entering names +;;; with lots of accents that would mess up mailers, or when for any +;;; reason you want the printed version of the name to be different +;;; from the version that appears on outgoing mail and in the *BBDB* +;;; buffer. You may want to add tex-name to a omit list of the variable +;;; bbdb-display-layout-alist so you only see it in the printout. +;;; tex-name is exempted from the usual special-character quoting done by +;;; bbdb-print; it is used verbatim. +;;; +;;; Not all fields or records need be printed. To not print a certain +;;; field, add it to `bbdb-print-omit-fields' (which see). If after eliding +;;; fields a record contains no interesting information, it will not +;;; be printed at all; the variable `bbdb-print-require' determines +;;; what is meant by "interesting" information. You can also restrict +;;; printing to just the records currently in the *BBDB* buffer by +;;; using *P instead of P. +;;; +;;; There are various options for the way the formatting is done; most +;;; are controlled by the variable bbdb-print-alist. See its +;;; documentation for the allowed options. + +;; +;; $Id: bbdb-print.el,v 1.6 2005/07/24 15:22:58 waider Exp $ +;; +;; $Log: bbdb-print.el,v $ +;; Revision 1.6 2005/07/24 15:22:58 waider +;; sync with Sourceforge CVS +;; +;; Revision 1.68 2004/10/13 13:37:06 waider +;; * Correct variable name in comment +;; +;; Revision 1.67 2001/11/19 21:35:08 waider +;; Patch from Alex Schroeder +;; +;; Revision 1.66 2001/09/11 10:55:31 fenk +;; Appliend fixed according to change log +;; +;; Revision 1.65 2000/11/27 12:59:53 waider +;; Alex's zipcode changes. WARNING: New database format. +;; +;; Revision 1.64 2000/07/13 17:07:00 sds +;; minor doc fixes to comply with the standards +;; +;; Revision 1.63 2000/05/29 22:47:50 waider +;; *** empty log message *** +;; +;; Revision 1.62 2000/04/15 17:11:49 kuepper +;; Adopt TeX-output of streets to new file-format v5. +;; +;; Revision 1.61 2000/04/13 17:19:58 kuepper +;; Improved TeX output (fonts, breaks). +;; +;; Revision 1.60 2000/04/13 00:22:23 waider +;; * Address layout patch, including Euro addresses and the streets->list thing +;; +;; Revision 1.59 1998/11/02 07:08:14 simmonmt +;; Change mailing list address +;; +;; Revision 1.58 1998/10/17 19:43:26 simmonmt +;; Patch to convert default area code protection from condition-case to +;; integerp. +;; +;; Revision 1.57 1998/04/11 07:19:32 simmonmt +;; Colin Rafferty's patch adding autoload cookies back +;; +;; Revision 1.56 1998/03/10 07:37:42 simmonmt +;; Protecting bbdb-default-area-code +;; +;; Revision 1.55 1998/02/23 07:12:40 simmonmt +;; Moved key binding to bbdb.el, changed default of bbdb-print-elide, +;; fixed problem with nil bbdb-default-area-code +;; +;; Revision 1.54 1998/01/06 06:08:38 simmonmt +;; Customized variables and removed autoloads +;; +;; Revision 1.53 1997/12/01 05:02:28 simmonmt +;; Soren Dayton's fix to correct tilde printing +;; +;; Revision 1.52 1997/10/06 01:05:28 simmonmt +;; New version of bbdb-print from Boris Goldowsky +;; +;; + +;;; Installation: +;;; +;;; Put this file somewhere on your load-path. Put bbdb-print.tex and +;;; bbdb-cols.tex somewhere on your TEXINPUTS path, or put absolute +;;; pathnames into the variable bbdb-print-format-files (which see). Put +;;; (add-hook 'bbdb-load-hook (function (lambda () (require 'bbdb-print)))) +;;; into your .emacs, or autoload it. +;;; +;;; This program was adapted for BBDB by Boris Goldowsky +;;; and Dirk Grunwald +;;; using a TeX format designed by Luigi +;;; Semenzato . +;;; We are also grateful to numerous people on the bbdb-info +;;; mailing list for suggestions and bug reports. + +;;; Code: + +(require 'bbdb) +(require 'bbdb-com) + +;;; Variables: + +(defcustom bbdb-print-file-name "~/bbdb.tex" + "*Default file name for printouts of BBDB database." + :group 'bbdb-utilities-print + :type 'file) + +(defcustom bbdb-print-omit-fields '(omit tex-name aka mail-alias) + "*List of fields NOT to print in address list. +See also bbdb-print-require." + :group 'bbdb-utilities-print + :type '(repeat (symbol :tag "Field to exclude"))) + +(defcustom bbdb-print-require '(or address phone) + "*What fields are required for printing a record. +This is evaluated for each record, and the record will be printed only +if it returns non-nil. The symbols name, company, net, phone, +address, and notes will be set to appropriate values when this is +evaluated; they will be nil if the field does not exist or is elided. + +The value of this variable can be any lisp expression, but typically +it will be used for a boolean combination of the field variables, as +in the following simple examples: + + Print only people whose phone numbers are known: + (setq bbdb-print-require 'phone) + Print people whose names AND companies are known: + (setq bbdb-print-require '(and name company)) + Print people whose names, and either addresses OR phone numbers are known: + (setq bbdb-print-require '(and name (or address phone)))." + :group 'bbdb-utilities-print + :type '(choice (const :tag "Print all records" t) + (symbol :tag "Print all records with this field" phone) + (sexp :tag "Print only when this evaluates to non-nil" + '(or phone address phone)))) + +(defun bbdb-print-field-shown-p (field) + (not (memq field bbdb-print-omit-fields))) + +(define-widget 'bbdb-print-alist-widget 'repeat + "For use in Customize" + :args `((choice + (cons :tag "Column specification" :value (column . 1) + (const :tag "Column mode" column) + (radio-button-choice (const :tag "One column" 1) + (const :tag "Two columns" 2) + (const :tag "Three columns" 3) + (const :tag "Four columns" 4) + (const :tag "Quad" quad) + (const :tag "Grid" grid))) + (cons :tag "Separator specification" :value (separator . 0) + (const :tag "Separator" separator) + (radio-button-choice (const :tag "None" 0) + (const :tag "Line" 1) + (const :tag "Boxed letters" 2) + (const :tag "Large boxed letters" 3) + (const :tag "Large letters" 4) + (const :tag "Letters with lines" 5) + (const :tag "Letters with suits" 6) + (const :tag "Boxed letters with suits" 7))) + (cons :tag "Omit certain area codes" + :value (omit-area-code . ,(concat "^(" + (if (integerp bbdb-default-area-code) + (int-to-string bbdb-default-area-code) + "000") ") ")) + (const :tag "Omit certain area codes" omit-area-code) + (regexp :tag "Pattern to omit")) + (cons :tag "Phone number location" :value (phone-on-first-line . t) + (const :tag "Phone number location" phone-on-first-line) + (choice (const :tag "First home number on same line as name" t) + (const :tag "Don't put the phone number on the name line" nil) + (regexp :tag "Use phone number whose location matches" "^work$"))) + (cons :tag "Limit included phone numbers" :value (n-phones . 3) + (const :tag "Limit included phone numbers" n-phones) + (integer :tag "Maximum number to include" 3)) + (cons :tag "Limit included addresses" :value (n-addresses . 3) + (const :tag "Limit included addresses" n-addresses) + (integer :tag "Maximum number to include" 3)) + (cons :tag "Include additional TeX input files" :value (include-files . nil) + (const :tag "Additional TeX input files to include" include-files) + (repeat (file :tag "TeX file to include"))) + (cons :tag "Font type selection" :value (ps-fonts . nil) + (const :tag "Select font type" ps-fonts) + (choice (const :tag "Use standard TeX fonts" nil) + (const :tag "Use Postscript fonts" t))) + (cons :tag "Font size selection" :value (font-size . 10) + (const :tag "Select font size" font-size) + (integer :tag "Font size in points" 10)) + (cons :tag "Page height selection" :value (v-size . nil) + (const :tag "Select page height" v-size) + (choice (const :tag "Use TeX default" nil) + (string :tag "Height (must be valid TeX dimension)" "9in"))) + (cons :tag "Page width selection" :value (h-size . nil) + (const :tag "Select page width" h-size) + (choice (const :tag "Use TeX default" nil) + (string :tag "Width (must be valid TeX dimension)" "6in"))) + (cons :tag "Vertical offset (top margin)" :value (voffset . nil) + (const :tag "Select vertical offset (top margin)" voffset) + (choice (const :tag "Use TeX default" nil) + (string :tag "Vertical offset (must be valid TeX dimension)" "1in"))) + (cons :tag "Horizontal offset (left margin)" :value (hoffset . nil) + (const :tag "Select horizontal offset (left margin)" hoffset) + (choice (const :tag "Use TeX default" nil) + (string :tag "Horizontal offset (must be valid TeX dimension)" "1in"))) + (cons :tag "Quad format height" :value (quad-vsize . "") + (const :tag "Select height for quad format pages" quad-vsize) + (string :tag "Height (must be valid TeX dimension)")) + (cons :tag "Quad format width" :value (quad-hsize . "") + (const :tag "Select width for quad format pages" quad-hsize) + (string :tag "Width (must be valid TeX dimension)"))))) + +(defcustom bbdb-print-alist + `((omit-area-code . ,(concat "^(" (if (integerp bbdb-default-area-code) + (int-to-string bbdb-default-area-code) + "000") ") ")) + (phone-on-first-line . "^[ \t]*$") + (ps-fonts . nil) + (font-size . 6) + (quad-hsize . "3.15in") + (quad-vsize . "4.5in")) + "*Formatting options for `bbdb-print', all formats. +This is an alist of the form ((option1 . value1) (option2 . value2) ...) + +You can have separate settings for brief and non-brief printouts; +see the variables `bbdb-print-brief-alist' and `bbdb-print-full-alist'. +Settings there will override the common settings in this variable. + +The possible options and legal values are: + - columns: 1, 2, 3, 4 or 'quad (4 little 2-column pages per sheet) + or 'grid (12 credit-card-sized pages per sheet). + - separator: 0-7, the style of heading for each letter. + 0=none, 1=line, 2=boxed letters, 3=large boxed letters, 4=large letters, + 5=letters with lines, 6=letters with suits, 7=boxed letters with suits. + - omit-area-code: a regular expression matching area codes to omit. + - phone-on-first-line: t means to put first phone number on the same + line with the name, nil means just the name. A string means to + use the first phone number whose \"location\" matches that string, + which should be a valid regular expression. + - n-phones: maximum number of phone numbers to include. + - n-addresses: maximum number of addresses to include. + - include-files: list of TeX files to \\input. If these filenames are not + absolute, the files must be located somewhere that TeX will find them. + - ps-fonts: nonnil means to use them, nil to use standard TeX fonts. + - font-size: in points, any integer (assuming fonts in that size exist!). + - hsize, vsize: horizontal dimension of pages. String value can be any valid + TeX dimension, or nil to use TeX's default. + - hoffset, voffset: shift TeX's output rightward (downward) by this distance + (any TeX dimension). Nil or 0 uses TeX's default positioning. + - quad-hsize, quad-vsize: for the quad format, horizontal and + vertical size of the little pages. These must be strings which + are valid TeX dimensions, eg \"10cm\"." + :group 'bbdb-utilities-print + :type 'bbdb-print-alist-widget) + +(defcustom bbdb-print-full-alist + '((columns . 3) + (separator . 2) + (include-files "bbdb-print" "bbdb-cols")) + "*Extra options for `bbdb-print' non-brief format. +These supplement or override entries in `bbdb-print-alist'; see description +of possible contents there." + :group 'bbdb-utilities-print + :type 'bbdb-print-alist-widget) + +(defcustom bbdb-print-brief-alist + '((columns . 1) + (separator . 1) + (n-phones . 2) + (n-addresses . 1) + (include-files "bbdb-print-brief" "bbdb-cols")) + "*Extra Options for `bbdb-print', brief format. +These supplement or override entries in `bbdb-print-alist'; see description +of possible contents there." + :group 'bbdb-utilities-print + :type 'bbdb-print-alist-widget) + +(defconst bbdb-print-filofax-alist + (append '((font-size . 12) + (columns . 2) + (voffset . "-2cm") + (hoffset . "-2cm") + (vsize . "27cm")) + bbdb-print-full-alist) + "Example setup for making pages for a Filofax binder.") + + +(defcustom bbdb-print-prolog + (concat "%%%% ====== Phone/Address list in -*-TeX-*- Format =====\n" + "%%%% produced by bbdb-print, version 3.0\n\n") + "*TeX statements to include at the beginning of the `bbdb-print' file." + :group 'bbdb-utilities-print + :type '(text :format "%t:\n%v")) + +(defcustom bbdb-print-epilog "\\endaddresses\n\\bye\n" + "*TeX statements to include at the end of the `bbdb-print' file." + :group 'bbdb-utilities-print + :type '(text :format "%t:\n%v")) + +(defcustom bbdb-print-net 'primary + "*Indicates whether only the primary or all email addresses are printed. +Symbol `primary' means print the primary email address only. +Symbol `all' means print all email addresses." + :group 'bbdb-utilities-print + :type '(choice (const primary) + (const all))) + +;;; Functions: + +(defsubst bbdb-print-if-not-blank (string &rest more) + "If STRING is not null, then return it concatenated +with rest of arguments. If it is null, then all arguments are +ignored and the null string is returned." + (if (or (null string) (equal "" string)) + "" + (apply 'concat string more))) + +;;;###autoload +(defun bbdb-print (visible-records to-file brief) + "Make a TeX file for printing out the bbdb database.\\ +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb-print]\" is \ +used instead of simply \"\\[bbdb-print]\", then includes only the +people currently in the *BBDB* buffer. With a prefix argument, makes +a brief \(one-line-per-entry) printout. + +There are various variables for customizing the content & format of +the printout, notably the variables `bbdb-print-alist' and +`bbdb-print-require'. See the file bbdb-print.el for more information." + (interactive (list (bbdb-do-all-records-p) + (read-file-name "Print To File: " + (file-name-directory bbdb-print-file-name) + bbdb-print-file-name + nil + (file-name-nondirectory bbdb-print-file-name)) + current-prefix-arg)) + (setq bbdb-print-file-name (expand-file-name to-file)) + (let* ((alist (append (if brief bbdb-print-brief-alist bbdb-print-full-alist) + bbdb-print-alist)) + (records (if (not visible-records) + (bbdb-records) + (set-buffer bbdb-buffer-name) + (mapcar 'car bbdb-records))) + (psstring (if (cdr (assoc 'ps-fonts alist)) + "ps" "")) + (columns (cdr (assoc 'columns alist))) + (current-letter t) + (pofl (cdr (assoc 'phone-on-first-line alist))) + (n-phones (cdr (assoc 'n-phones alist))) + (n-addresses (cdr (assoc 'n-addresses alist)))) + (find-file bbdb-print-file-name) + (widen) (erase-buffer) + (insert bbdb-print-prolog) + (let ((dimens '(hsize vsize hoffset voffset)) + val) + (while dimens + (setq val (cdr (assoc (car dimens) alist))) + (if val + (insert (format "\\%s=%s\n" (car dimens) val))) + (setq dimens (cdr dimens)))) + (let ((infiles (cdr (assoc 'include-files alist)))) + (while infiles + (insert (format "\\input %s\n" (car infiles))) + (setq infiles (cdr infiles)))) + (insert (format "\n\\set%ssize{%d}\n" + psstring (cdr (assoc 'font-size alist))) + (format "\\setseparator{%d}\n" + (cdr (assoc 'separator alist))) + (cond ((eq 'quad columns) + (format "\\quadformat{%s}{%s}" + (cdr (assoc 'quad-hsize alist)) + (cdr (assoc 'quad-vsize alist)))) + ((eq 'grid columns) "\\grid") + ((= 4 columns) "\\fourcol") + ((= 3 columns) "\\threecol") + ((= 2 columns) "\\twocol") + ((= 1 columns) "\\onecol")) + ;; catcodes are font-encoding specific ! + ;; Add more if you know them + (if (equal psstring "ps") + (concat "\n\n" + ;; Adobe Times and Courier + ) + (concat "\n\n" + ;; ec fonts + "\\catcode`ß=\\active\\chardefß=\"FF")) + "\n\n\\beginaddresses\n") + (while records + (setq current-letter + (bbdb-print-format-record (car records) current-letter + brief pofl n-phones n-addresses)) + (setq records (cdr records))) + (insert bbdb-print-epilog) + (goto-char (point-min)))) + +(defvar bbdb-address-print-formatting-alist + '((bbdb-address-is-continental . bbdb-print-format-address-continental) + (nil . bbdb-print-format-address-default)) + "Alist of address identifying and address formatting functions for printing. +The key is an identifying function which accepts an address. The +associated value is a formatting function which inserts the formatted +address in the current buffer. If the identifying function returns +non-nil, the formatting function is called. The nil key is a default +value will allways calls the associated formatting function. Therefore +you should always have (nil . bbdb-print-format-address-default) as the +last element in the alist. + +The functions must take one argument, the address. + +See also `bbdb-address-formatting-alist'.") + +(defun bbdb-print-format-address-continental (addr) + "Insert formated continental address ADDR in current buffer for printing. +This format is used in western Europe, for example. + +This function is a possible formatting function for +`bbdb-address-print-formatting-alist'. + +The result looks like this: + street + street + ... + zip city, state + country" + (insert + (format + "\\address{%s}\n" + (bbdb-print-tex-quote + (if addr + (concat + (mapconcat (function (lambda(str) + (if (= 0 (length (bbdb-string-trim str))) + () + (concat str"\\\\\n")))) + (bbdb-address-streets addr) + "") + (let ((c (bbdb-address-city addr)) + (s (bbdb-address-state addr)) + (z (bbdb-address-zip addr))) + (if (or (> (length c) 0) + (> (length z) 0) + (> (length s) 0)) + (concat z (if (and (> (length z) 0) + (> (length c) 0)) " " "") + c (if (and (or (> (length z) 0) + (> (length c) 0)) + (> (length s) 0)) ", " "") + s "\\\\\n") "")) + (bbdb-print-if-not-blank (bbdb-address-country addr) "\\\\\n")) + ""))))) + +(defun bbdb-print-format-address-default (addr) + "Insert formated address ADDR in current buffer for printing. +This is the default format; it is used in the US, for example. + +This function is a possible formatting function for +`bbdb-address-print-formatting-alist'. + +The result looks like this: + street + street + ... + city, state zip + country" + (insert + (format + "\\address{%s}\n" + (bbdb-print-tex-quote + (if addr + (concat + (mapconcat (function (lambda(str) + (if (= 0 (length (bbdb-string-trim str))) + () + (concat str "\\\\\n")))) + (bbdb-address-streets addr) + "") + (let ((c (bbdb-address-city addr)) + (s (bbdb-address-state addr)) + (z (bbdb-address-zip addr))) + (if (or (> (length c) 0) + (> (length z) 0) + (> (length s) 0)) + (concat c (if (and (> (length c) 0) + (> (length s) 0)) ", " "") + s (if (and (or (> (length c) 0) + (> (length s) 0)) + (> (length z) 0)) " " "") + z "\\\\\n") "")) + (bbdb-print-if-not-blank (bbdb-address-country addr) "\\\\\n")) + ""))))) + +(defun bbdb-print-format-record (record current-letter + brief pofl n-phones n-addresses) + "Insert the bbdb RECORD in TeX format. +Second arg CURRENT-LETTER is the first letter of the sortkey of the previous +record. If this is non-nil and RECORD begins differently, a section heading is +output. If CURRENT-LETTER is t always produces a heading. +3rd argument BRIEF is for 1-line-per-record printouts. +Args 3-5 PHONE-ON-FIRST-LINE, N-PHONES, and N-ADDRESSES are the respective +values from `bbdb-print-alist'. + +The return value is the new CURRENT-LETTER." + + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: tex formatting deleted record"))) + + (let* ((first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-print-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-print-tex-quote + (bbdb-record-name record))))) + (company (and (bbdb-print-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-print-field-shown-p 'net) + (bbdb-record-net record))) + (phone (and (bbdb-print-field-shown-p 'phone) + (bbdb-record-phones record))) + (address (and (bbdb-print-field-shown-p 'address) + (bbdb-record-addresses record))) + (notes (bbdb-record-raw-notes record))) + + (if (not (eval bbdb-print-require)) + nil ; lacks required fields + + ;; Section header, if neccessary. + + (if (and current-letter + (not (string-equal first-letter current-letter))) + (insert (format "\\goodbreak\n\\separator{%s}\n%%\n" + (bbdb-print-tex-quote (upcase first-letter))))) + + (insert "\\beginrecord\n") + + ;; if there is no name, use company instead + (if (and (not name) company) + (setq name (bbdb-print-tex-quote company) + company nil)) + + (let ((rightside "")) + (cond ((null phone)) + ((eq t pofl) + (setq rightside (bbdb-print-phone-string (car phone)) + phone (cdr phone))) + ((stringp pofl) + (let ((p (bbdb-print-front-if + (function (lambda (ph) + (string-match pofl (aref ph 0)))) + phone))) + (if p + (setq rightside (bbdb-print-phone-string (car p)) + phone (cdr p)))))) + (insert (format "\\firstline{%s}{%s}\n" + name + (bbdb-print-tex-quote rightside)))) + + (if company + (insert (format "\\comp{%s}\n" (bbdb-print-tex-quote company)))) + + ;; Phone numbers + + (if n-phones + (setq phone (bbdb-print-firstn (- n-phones (if pofl 1 0)) + phone brief))) + (while phone + (if (car phone) + (let ((place (aref (car phone) 0)) + (number (bbdb-print-phone-string (car phone)))) + (insert (format "\\phone{%s%s}\n" + (bbdb-print-tex-quote + (bbdb-print-if-not-blank place ": ")) + (bbdb-print-tex-quote number)))) + (insert (format "\\phone{}\n"))) + (setq phone (cdr phone))) + + ;; Email address + ;; Make all dots legal line-breaks. + + (when net + (let ((net-addrs + (cond ((eq bbdb-print-net 'primary) + (list (car net))) + ((eq bbdb-print-net 'all) + net) + (t nil)))) + (insert + (format + "\\email{%s}\n" + (mapconcat + (lambda (net-addr) + (setq net-addr (bbdb-print-tex-quote net-addr)) + (let ((start 0)) + (while (string-match "\\." net-addr start) + (setq net-addr + (concat (substring net-addr 0 (match-beginning 0)) + ".\\-" + (substring net-addr (match-end 0)))) + (setq start (+ 2 (match-end 0))))) + net-addr) + net-addrs ", "))))) + + ;; Addresses. FUTURE: If none left, should use phones instead. + + (if n-addresses + (setq address + (bbdb-print-firstn n-addresses address brief))) + (while address + (bbdb-format-address (car address) 'printing) + (setq address (cdr address))) + + ;; Notes + + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + (while notes + (let ((thisnote (car notes))) + (if (bbdb-print-field-shown-p (car thisnote)) + (progn + (if (eq 'notes (car thisnote)) + (insert (format "\\notes{%s}\n" (bbdb-print-tex-quote + (cdr thisnote)))) + (insert (format "\\note{%s}{%s}\n" + (bbdb-print-tex-quote (symbol-name + (car thisnote))) + (bbdb-print-tex-quote (cdr thisnote)))))))) + (setq notes (cdr notes))) + + ;; Mark end of the record. + + (insert "\\endrecord\n%\n") + (setq current-letter first-letter))) + + current-letter) + +(defun bbdb-print-phone-string (phone) + "Format PHONE-NUMBER as a string, obeying omit-area-code setting. +Omit-area-code is one of the allowed symbols in `bbdb-print-alist', which see." + (let ((str (bbdb-phone-string phone)) + (omit (cdr (assoc 'omit-area-code bbdb-print-alist)))) + (if (and omit (string-match omit str)) + (substring str (match-end 0)) + str))) + +(defun bbdb-print-front-if (func list) + "Move first elt of LIST satisfying FUNC to front. +The car of the returned list is the first element that returned nonnil; +The cdr is the rest of the list. +But if the FUNC returns nil for every elements of the LIST, returns nil." + (cond ((null list) nil) + ((funcall func (car list)) + list) + ((let ((rest (bbdb-print-front-if func (cdr list)))) + (if rest + (cons (car rest) + (cons (car list) (cdr rest)))))))) + +(defun bbdb-print-firstn (n list force) + "The first N elements of LIST. +If 3rd arg FORCE is nonnil, will extend the list to length N if necessary, by +adding nil's. If N is nil, just returns LIST." + (cond ((null n) list) + ((null list) (if force (make-list n nil) nil)) + ((<= n 0) nil) + (t (cons (car list) (bbdb-print-firstn (1- n) (cdr list) force))))) + +(defun bbdb-print-tex-quote (string) + "Quote any unquoted TeX special characters that appear in STRING. +In other words, # alone will be replaced by \\#, but \\^ will be left for +TeX to process as an accent." + (if string + (save-excursion + (set-buffer (get-buffer-create " bbdb-print-tex-quote")) + (erase-buffer) + (insert string) + (goto-char (point-min)) + (while (not (eobp)) + (cond ((looking-at "[<>=]+") + (replace-match "$\\&$")) + ((and (looking-at "[#$%&_]") + (not (eq ?\\ (char-after (1- (point)))))) + (insert "\\") + (forward-char 1)) + ((and (looking-at "~") + (not (eq ?\\ (char-after (1- (point)))))) + (insert "\\") + (forward-char 1) + (insert "{}")) + ((and (looking-at "[{}]") + (not (eq ?\\ (char-after (1- (point)))))) + (insert "$\\") + (forward-char 1) + (insert "$")) + (t (forward-char 1)))) + (buffer-string)))) + + +(provide 'bbdb-print) + +;;; bbdb-print ends here. + diff --git a/xemacs-packages/lisp/bbdb/bbdb-print.elc b/xemacs-packages/lisp/bbdb/bbdb-print.elc new file mode 100644 index 0000000000000000000000000000000000000000..1419e16feca93be93aeabbd4de930867cb5adadd GIT binary patch literal 17833 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

L_m-6f!+ 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-reportmail.el b/xemacs-packages/lisp/bbdb/bbdb-reportmail.el new file mode 100644 index 00000000..c2173cb3 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-reportmail.el @@ -0,0 +1,111 @@ +;; bbdb-reportmail.el --- Hooks the Insidious Big Brother Database +;; into the Reportmail package + +;; Copyright (C) 1997 Christopher Kline + +;; Author: Christopher Kline +;; Maintainer: Christopher Kline +;; Version: 1.01 +;; Created: 25 Jun 1997 +;; Date: 26 Jun 1997 + +;; Bbdb-reportmail 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. + +;; Bbdb-reportmail 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. + +;;; Commentary: + +;; Bbdb-reportmail advises the reportmail package function +;; display-time-get-field so that it attempts to replace the reported +;; "from" and "to" fields with the name field (or mail-name, if it +;; exists) of the corresponding BBDB record, if such a correspondence +;; can be made. + +;; To use this, simply add the following lines AFTER you load in your +;; bbdb, set bbdb variables, etc. +;; +;; (bbdb-insinuate-reportmail) +;; +;; (A require used to be necessary - it is no longer needed as long as +;; bbdb-insinuate-reportmail is called) + +;;; History: + +;; v1.01 26 June 1997 +;; Fixed the advice so that if we are the message recipient, do +;; nothing so that display-time-process-new-mail will correctly +;; trap this case. +;; +;; v1.00 26 June 1997 +;; Initial release. + +;; +;; $Id: bbdb-reportmail.el,v 1.6 2005/07/24 15:22:58 waider Exp $ +;; + +;;----------------------------------------------------------------------- + +(require 'bbdb) +(require 'reportmail) +(require 'advice) +(require 'mail-extr) + +(defun bbdb/reportmail-alternate-full-name (address) + (if address + (let ((entry (bbdb-search-simple nil address))) + (if entry + (or (bbdb-record-getprop entry 'mail-name) + (bbdb-record-name entry)))))) + +(defadvice display-time-get-field + (around bbdb/reportmail-hack-display-time-get-field disable activate) + "Advises the `display-time-get-field' function in the reportmail package. +If the field is \"from\" or \"to\", it tries to replace the value of the field +with the name field of the corresponding BBDB entry, if one can be found. + +If no corresponding record can be found, the field value is left unaltered." + (let (gf-field) + ;; Get the original argument to display-time-get-field + (setq gf-field (ad-get-arg 0)) + ;; Call the original display-time-get-field + ad-do-it + (if (or (string= gf-field "To") (string= gf-field "From")) + (setq ad-return-value + (or + ;; If this message is to me, then do nothing so + ;; reportmail can trap this case in + ;; display-time-process-new-mail + (if (display-time-member ad-return-value + display-time-my-addresses) + ad-return-value + nil) + ;; Is the sender/recipient in our BBDB? + (bbdb/reportmail-alternate-full-name + (car (cdr (mail-extract-address-components ad-return-value)))) + ;; Can't find sender/recipient in BBDB; do nothing. + ad-return-value) + )))) + +;;;###autoload +(defun bbdb-insinuate-reportmail () + "Call this function to hook BBDB into reportmail." + (ad-enable-advice 'display-time-get-field 'around + 'bbdb/reportmail-hack-display-time-get-field) + (ad-activate 'display-time-get-field) + (message "Insinuated BBDB into Reportmail.") +) + +(provide 'bbdb-reportmail) + + diff --git a/xemacs-packages/lisp/bbdb/bbdb-reportmail.elc b/xemacs-packages/lisp/bbdb/bbdb-reportmail.elc new file mode 100644 index 0000000000000000000000000000000000000000..f48c204a3857068aeb09309dd43272cffcc34923 GIT binary patch literal 2686 zcmcIm&2JM&6sNb?Br95=O@KJh8>DzCYdeMrNL0yz(iT*yQmND;HWK6AS$mZA%(5Rb z>8))l9JusGPdy=3ij(xxLywRIL+Ka&{&)Ij*2a!W+Y^@7yF2sdz2E!#y`8)G?uA49 z_U%j0&CP)=>OS+R1C?dqi)9iJmwNdn7EvzpoJJrxe2Clc*%3^aV7fS4JU4s#43vt+ z8KuAtL>*jI0fjgW3ZAfuhfg#J3w*KQFILS;%si(M(J(69q;+D4rcdleQl(*`QgJE; zkA=Q^G6U+1AgUAQ<*BE%D|uK#Z47~wrt_yE=aa~;!Sope^viL*BH&6bV0B-Ik1k5> z@NR4~C$ElImLn=X>}klC&UEDFqz^^2c+Q+ICDOu=Se<=LB58|-=z6jq)$m2Rh<@R+ zZwm+SjT%E7jsPwqpf_0<0ppNhm_C! zo1N{-0EVRh9nZ*LE{p=ktENZ8(1%@WK`#|`!!XiHjs^jm(67r#?~d;jG)UOXzl&lC zc6A)lOK4r-b{qthN2Vu;V`9Q010m4p20XU`oOx&*&&%MOGE|`7e~@k7-@YgB#yJsH_k-5*Nb+GhLcNbBqU>-V0Fl=qbTQ^_41nO{A;es#am z&WvY9SC6$;w9)l1hFdGc<<0N3(T#7l(em0i!>zU9vNk%J$qcpb4wbbGY29wG9yp|B zUL9ZahUQlfth3?PXT$S{POM$g#?95t#KxV!w28kheRJihHjy=CGO*D@OaeBKiXY)& zg9hpuYeudj5nx`SsM00ZMBs!V3tmRw422sdTb0;#@o1Gs*!S|$Y%uPK26Wz({@yO+ z`pYEMTG>ivo7+1NExkD;fvK{sk+2q#3Q|l1Lh4aFdZsj~>I97h7%jjl!{|quRKzLJ zbs)Y^WjDSMlP^YVr){N!CPvKkHbG-TR!H%WN_+z)DEMBT99b{^cESpG^RKhV`MmjFVUCt>>2P8F1kA$V41Qr33s5B=e0eJ*zM_OJYUQ9vsX|Q;MMK!gl;-0AONMLS| zX?(#QBxE>${>}5Cf{X@S93d2J!l6RJl`{aLDR5jM^Y))hT56Z<$vzhnOz4P5vD0F% zSdTh+9daI~H&=C&Ty$x<`!2(*GDU(a6tOe#)e$DTu7;DO_+*m20nd);9|&FQQ4^+r z{Vfb3PL>Yyqb97Z7`s0Kr{;y6c)Jo;r}YZ*!JzPNnPpjIlCCKd_Mj*h3z{4(vAt+N zXA|_tcJS}n_#j9Y9pyNS>X;@>PB>@;$K`W|<(ga#WZqPLA~ICRmgKMzd;w;R^kjLa z2p5Ql%%eUMy0wWVRTE+{DF-A;Rbkz4n~A}BW-=Z!9!tG_)jWAk_6g3;t?kL?4o=XA zZ8bR&2IZ0t|EDcG$Oj|$U(MO)A=EJ+_>l(sr7k$9&z<*spKAI7;8)q?amYjI)Y%zB SQVJ5)62r-_#&w@lM*1JaRi>=~ literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-rmail.el b/xemacs-packages/lisp/bbdb/bbdb-rmail.el new file mode 100644 index 00000000..63f0bd84 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-rmail.el @@ -0,0 +1,179 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file is part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992 Jamie Zawinski . +;;; Interface to RMAIL. See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-rmail.el,v 1.6 2005/07/24 15:22:58 waider Exp $ +;; + +(eval-when-compile + (require 'bbdb) + (require 'bbdb-com) + (require 'rmail) + ;(require 'rmailsum) ; not provided, dammit! + (if (not (fboundp 'rmail-make-summary-line)) + (load-library "rmailsum")) + ;; just to avoid a warning + (if (not (boundp 'rmail-buffer)) + (defvar rmail-buffer nil))) + +;;;###autoload +(defun bbdb/rmail-update-record (&optional offer-to-create) + (let ((bbdb-get-only-first-address-p) + (records (bbdb/rmail-update-records offer-to-create))) + (if records (car records) nil))) + +(defun bbdb/rmail-update-records (&optional offer-to-create) + "Returns the records corresponding to the current RMAIL message, creating or +modifying it as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." + (if bbdb-use-pop-up + (bbdb/rmail-pop-up-bbdb-buffer offer-to-create) + (if (and (boundp 'rmail-buffer) rmail-buffer) + (set-buffer rmail-buffer)) + (if rmail-current-message + (let ((records (bbdb-message-cache-lookup rmail-current-message)) + record) + (or records + (save-excursion + (let ((from (mail-fetch-field "from"))) + (if (or (null from) + (string-match (bbdb-user-mail-names) + (mail-strip-quoted-names from))) + ;; if logged-in user sent this, use recipients. + (setq from (or (mail-fetch-field "to") from))) + (if from + (setq record + (bbdb-annotate-message-sender + from t + (or (bbdb-invoke-hook-for-value + bbdb/mail-auto-create-p) + offer-to-create) + offer-to-create))) + ;; return a list of records + (if record + (bbdb-encache-message + rmail-current-message + (list record)))))))))) + +;;;###autoload +(defun bbdb/rmail-annotate-sender (string &optional replace) + "Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." + (interactive (list (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.") + (read-string "Comments: ")))) + (if (and (boundp 'rmail-buffer) rmail-buffer) + (set-buffer rmail-buffer)) + (bbdb-annotate-notes (bbdb/rmail-update-record t) string 'notes replace)) + +(defun bbdb/rmail-edit-notes (&optional arg) + "Edit the notes field or (with a prefix arg) a user-defined field +of the BBDB record corresponding to the sender of this message." + (interactive "P") + (let ((record (or (bbdb/rmail-update-record t) (error "")))) + (bbdb-display-records (list record)) + (if arg + (bbdb-record-edit-property record nil t) + (bbdb-record-edit-notes record t)))) + + +;;;###autoload +(defun bbdb/rmail-show-sender () + "Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." + (interactive) + (if (and (boundp 'rmail-buffer) rmail-buffer) + (set-buffer rmail-buffer)) + (let ((record (bbdb/rmail-update-record t))) + (if record + (bbdb-display-records (list record)) + (error "unperson")))) + + +(defun bbdb/rmail-pop-up-bbdb-buffer (&optional offer-to-create) + "Make the *BBDB* buffer be displayed along with the RMAIL window(s), +displaying the record corresponding to the sender of the current message." + (bbdb-pop-up-bbdb-buffer + (function (lambda (w) + (let ((b (current-buffer))) + (set-buffer (window-buffer w)) + (prog1 (eq major-mode 'rmail-mode) + (set-buffer b)))))) + (let ((bbdb-gag-messages t) + (bbdb-use-pop-up nil) + (bbdb-electric-p nil)) + (let ((records (bbdb/rmail-update-records offer-to-create)) + (b (current-buffer))) + (if records + (bbdb-display-records records bbdb-pop-up-display-layout) + (bbdb-undisplay-records) + (if (get-buffer-window bbdb-buffer-name) + (delete-window (get-buffer-window bbdb-buffer-name)))) + (set-buffer b) + records))) + +(defun bbdb/rmail-only-expunge () + "Actually erase all deleted messages in the file." + (interactive) + (setq bbdb-message-cache nil) + (bbdb-orig-rmail-only-expunge)) + +(defun bbdb/undigestify-rmail-message () + "Break up a digest message into its constituent messages. +Leaves original message, deleted, before the undigestified messages." + (interactive) + (setq bbdb-message-cache nil) + (bbdb-orig-undigestify-rmail-message)) + +;(defun bbdb-orig-rmail-expunge () +; "This becomes the original rmail-expunge function.") +;(defun bbdb-orig-undigestify-rmail-message () +; "This becomes the original rmail-expunge function.") + +;;;###autoload +(defun bbdb-insinuate-rmail () + "Call this function to hook BBDB into RMAIL." + (define-key rmail-mode-map ":" 'bbdb/rmail-show-sender) + (define-key rmail-mode-map ";" 'bbdb/rmail-edit-notes) + (define-key rmail-summary-mode-map ":" 'bbdb/rmail-show-sender) + (define-key rmail-summary-mode-map ";" 'bbdb/rmail-edit-notes) + + (add-hook 'rmail-show-message-hook 'bbdb/rmail-update-records) + + ;; We must patch into rmail-only-expunge to clear the cache, since expunging a + ;; message invalidates the cache (which is based on message numbers). + ;; Same for undigestifying. + (or (fboundp 'bbdb-orig-rmail-only-expunge) + (defalias 'bbdb-orig-rmail-only-expunge (symbol-function 'rmail-only-expunge))) + (defalias 'rmail-only-expunge 'bbdb/rmail-only-expunge) + + (or (fboundp 'undigestify-rmail-message) + (autoload 'undigestify-rmail-message "undigest" nil t)) + (if (eq (car-safe (symbol-function 'undigestify-rmail-message)) 'autoload) + (load (nth 1 (symbol-function 'undigestify-rmail-message)))) + (or (fboundp 'bbdb-orig-undigestify-rmail-message) + (defalias 'bbdb-orig-undigestify-rmail-message + (symbol-function 'undigestify-rmail-message))) + (defalias 'undigestify-rmail-message 'bbdb/undigestify-rmail-message) + ) + +(provide 'bbdb-rmail) diff --git a/xemacs-packages/lisp/bbdb/bbdb-rmail.elc b/xemacs-packages/lisp/bbdb/bbdb-rmail.elc new file mode 100644 index 0000000000000000000000000000000000000000..e4bff6e3bca40b520490d807aec19d4c631be6b5 GIT binary patch literal 4417 zcmb7HOLH5?5!R7_L`4TDkyTF8yHrJhii;NsQ6w)SDY{A#9XX7uk}88$UhEEl2^TZV z-C0t|Es-OFsY)*S2RRD1{y3$J>6e_{dLd$^2*W& z7cN}L&d<+-$J-$dh!6D+u=P7`^ACb1}#ZKsY>u!_8#d_VZ z7XuoH>X#F>T^bZfpbV>}u!)8!`cNqsrXd%)!fQc!CJ**+l6IZL?^_XVhc^6iSsI3w z#G`&eZLfC(k--ft6e=@j-Mn6<;y8p8X2GtM?0i0-RqIF;;Su)d668L#H(<++2U&063hlPq ziH=LJQlGsfiU<=JT(PQ(VB`2dUtcrNbuNy7~&o^eAZSEbZRLf;j{i7+FP z4-=o|ek}p#%ng7y8YFTAcf5$;8qDn8e#W|XwZ^{sYmMExxoyK|DuN~v4rf8fY0xMZ zj_dmoBH)ClEr32HmM+04AL2EbTFYlA?o_6#uu4P{u^2>)^f#lUXg=i3N320`_0fb4 ztDh{~TY)wnk1U=9<+)tOqimb|w9%0dQ~;vDh$ojtodUpuu?|}_K-Y-gh{Z)4S>>pt zzvCu-FfcfzALGoySSHatu7n34f4scvJbd6Rtu8M-T$U?Dln_9+Wn~1i_AtQ=VQTA` zw0}tHU;QuXiGM6Vmw(p#;^3mSefYK2dy?rr&TMosSqCp_%zF9J&M$xd>_2~h_1fC` zMekp4#-8mQy*&o&=yy9;-i=!|ySM%78|&F$#(z5A`^UHA-+h1iDn4Djc>RM*U;XWU zja^!***6C%m!UWc6y_q@pvhEEBxTG)%0!cl5o7?RQbS}2d5ENR6tRpwLwfbfSaUqr zYZ0VBUr$2CC*@3opb8-kN#KJmE!$vfvaR&VuGQ)`=DJB9h0aF8g-#0EX;Mrjh62it z++-H`>U9jZ;I<;I<1*A1Sv09HF=0N2E%ax~Hu*YnTIiaCMeJ<40dhb&PndQ)g+#qX zC>Zws{#E%xK&~N7Gsn;DG@QR z78ma>nxnGk7L$obEk_O;Z?R17HDGo5)0KrK#qE^+*@%RJ>*49haV5F3$Pgnu7&R*D zfYe-r#zUN6g+6q#Pzu z|2XZWg8Mu<6grAEs2beM)!7m%trT1plu96~qp##Igq%_Khls>I7E_<{B!)%WgvE#> zJQ3V=g;&RKi)X(WrVdp4&^j-A3%C(ucdWO4n0c``@$`$AnZ25wmx;r5hLI!t0+yEn*OZ};!%5(FOzVnuh3O9CD1X9; zha?g>J(+f6mg=v{+cm(^MO9R#bi0hy`qb7~S7za^wy)a@XE=5V95ZxPsS=VMTION| zR@sMgLNOAS_7$8(6lbs*VSCb9i(~Fl)Ds`pNvBR#UyDbUO5EaGPQOfKX!hG8XXrlf4+h4(M43JxA@oUUfSr6 zJA*OFZKf^5uysiK71|^q9(EoNrwjG0$)o#H-2`v8p6~Y-QaHS}m$5dwWBaa@M@4|P z`zLHfl5?;Hb%a~ui_`y5x0WB*pt6Q#mX^zTyfCMqriJnrr|DBADF;IngFX{{3=uo0 zc{&BI4%$SP+QJg&i5M!>nOnECAXZDT;EBWyf(}Z9)KvUwPVm#j$8!9a)RI?)kwvBC z8)t%qH3<$`s;a)evJ3s(rLA7|?><5fk7!d5@Ol6?Cf1;As$yzt2Cqc@s=#~BBI^7) z;Lze?8Q@Jzq@JRqILuNM85|K~K}CX!lYWc~*%jh$Vn>xnQaPR*mnPGQCvk2?Nzx@J zb0LjWY!L%2&WV4p5S3Jo9O-cK|H3fR(hwTe>a779(^XiK8Phkpgn8#;b#> zDV&2tGxN$SQjfapIw. +;;; +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;; This file was written by Martin Sjolin +;;; based the original code by Tom Tromey . +;;; +;;; Thanks to Richard Stanton for ideas +;;; for improvements and to Michael D. Carney +;;; for testing and feedback. + +;;; $Id: bbdb-sc.el,v 1.7 2005/07/24 15:22:58 waider Exp $ + +;;; This file adds the ability to define attributions for Supercite in +;;; a BBDB, enables you to retrieve your standard attribution from +;;; BBDB. If the from header in the mail to which you are replying +;;; only contains the e-mail address, the personal name is lookup in +;;; BBDB. You need Supercite to make this code work. The attribution +;;; os is stored under the key `attribution' (unless you've changed +;;; bbdb/sc-attribution-field). + +;;; To use enable this code you will have to the "sc-consult" to your +;;; sc-preferred-attribution-list. This file sets variable if it is not +;;; set and isues an warning message if "sc-consult" is not included. +;;; +;;; (setq sc-preferred-attribution-list +;;; '("sc-lastchoice" "x-attribution" "sc-consult" +;;; "initials" "firstname" "lastname")) +;;; +;;; +;;; We also set the sc-attrib-selection-list below if is not bound, if +;;; you have your own special sc-attrib-selection-list, please add +;;; an expression as below: +;;; +;;; (setq sc-attrib-selection-list +;;; '(("sc-from-address" ((".*" . (bbdb/sc-consult-attr +;;; (sc-mail-field "sc-from-address"))))))) +;;; +;;; And finally we set the sc-mail-glom-frame to enable the +;;; fetching of the name of person when there is only an e-mail +;;; address in the original mail: +;;; +;;; (setq sc-mail-glom-frame +;;; '((begin (setq sc-mail-headers-start (point))) +;;; ("^x-attribution:[ \t]+.*$" (sc-mail-fetch-field t) nil t) +;;; ("^\\S +:.*$" (sc-mail-fetch-field) nil t) +;;; ("^$" (progn (bbdb/sc-default) +;;; (list 'abort '(step . 0)))) +;;; ("^[ \t]+" (sc-mail-append-field)) +;;; (sc-mail-warn-if-non-rfc822-p (sc-mail-error-in-mail-field)) +;;; (end (setq sc-mail-headers-end (point))))) +;;; +;;; + +;;; +;;; + +;;; packages +(require 'bbdb) +(require 'supercite) + +;;; User variable(s) +(defcustom bbdb/sc-replace-attr-p t + "t if you like to create a new BBDB entry when +entering a non-default attribution, 'ask if the user +should be asked before creation and NIL if we never create a new entry." + :group 'bbdb-utilities-supercite + :type '(choice (const "Create a new BBDB entry" t) + (const "Confirm new record creation" ask) + (const "Don't create a new entry" nil))) + +(defcustom bbdb/sc-attribution-field 'attribution + "The BBDB field used for Supercite attribution information." + :group 'bbdb-utilities-supercite + :type '(symbol :tag "Field name")) + +;;; Code starts +(defcustom bbdb/sc-last-attribution "" + "Default attribution return by the SuperCite citation engine, +used to compare against citation selected by the user." + :group 'bbdb-utilities-supercite + :type '(string :tag "Default citation" "")) + +(defun bbdb/sc-consult-attr (from) + "Extract citing information from BBDB using sc-consult where +FROM is user e-mail address to look for in BBDB." + ;; if logged in user sent this, use recipients. + (let ((from (if (or (null from) + (string-match (bbdb-user-mail-names) from)) + (car (cdr (mail-extract-address-components + (or (sc-mail-field "to") from)))) + from))) + (if from + (let ((record (bbdb-search-simple nil from))) + (and record + (bbdb-record-getprop record bbdb/sc-attribution-field)))))) + +(defun bbdb/sc-set-attr () + "Add attribute to BBDB." + (let ((from (sc-mail-field "from")) + (address (sc-mail-field "sc-from-address")) + (attr (sc-mail-field "sc-attribution"))) + (if (and from attr bbdb/sc-replace-attr-p + (not (string-equal attr bbdb/sc-last-attribution)) + (not (string-match (bbdb-user-mail-names) address))) + (let* ((bbdb-notice-hook nil) + ;; avoid noticing any headers in the reply message + (record (bbdb-annotate-message-sender + from t + (bbdb-invoke-hook-for-value + bbdb/mail-auto-create-p) t))) + (if record + (let ((old (bbdb-record-getprop record 'attribution))) + ;; ignore if we have an value and same value + (if (and (not (and old (string-equal old attr))) + (or (not (eq bbdb/sc-replace-attr-p 'ask)) + (y-or-n-p (concat "Change attribution " attr)))) + (progn (bbdb-record-putprop record + bbdb/sc-attribution-field attr) + (bbdb-change-record record nil))))))))) + +;;; this is marked as autoload since someone managed to trip up Gnus +;;; with it. I'm not clear this needs fixing, as you should be calling +;;; bbdb-insinuate-sc if you're using supercite/BBDB. However. +;;;###autoload +(defun bbdb/sc-default () + "If the current \"from\" field in `sc-mail-info' alist +contains only an e-mail address, lookup e-mail address in +BBDB, and prepend a new \"from\" field to `sc-mail-info'." + (let* ((from (sc-mail-field "from")) + (pair (and from (mail-extract-address-components from)))) + (if (and pair (not (car pair))) + (let* ((record (bbdb-search-simple nil (car (cdr pair)))) + (name (and record (bbdb-record-name record)))) + (if name + (setq sc-mail-info + (cons (cons "from" + (format "%s (%s)" (car (cdr pair)) name)) + sc-mail-info))))))) + +;;; setup the default setting of the variables +(defun bbdb/sc-setup-variables () + "Set up the various Supercite variables for the BBDB. +`sc-preferred-attribution-list', `sc-attrib-selection-list', and +`sc-mail-glom-frame' are set, but only if they have not previously +been defined. It is strongly suggested that you not call this +function directly, but that you use this function (specifically the +settings contained herein) as an example. In other words, set these +variables yourself, either in your Emacs configuration file or using +Custom." + + ;; check for sc-consult in sc-preferred-attribution-list + (if (boundp 'sc-preferred-attribution-list) + (or (member '"sc-consult" sc-preferred-attribution-list) + (bbdb-warn (concat "\"sc-consult\" not included in " + "sc-preferred-attribution-list. Attributions cannot" + "be gathered from the BBDB without \"sc-consult\"" + "in sc-preferred-attribution-list"))) + (defvar sc-preferred-attribution-list + '("sc-lastchoice" "x-attribution" "sc-consult" + "initials" "firstname" "lastname"))) + + ;; check sc-attrib-selection-list + (defvar sc-attrib-selection-list + '(("sc-from-address" + ((".*" . (bbdb/sc-consult-attr + (sc-mail-field "sc-from-address"))))))) + + ;; set sc-mail-glom-frame + (defvar sc-mail-glom-frame + '((begin (setq sc-mail-headers-start (point))) + ("^x-attribution:[ \t]+.*$" (sc-mail-fetch-field t) nil t) + ("^\\S +:.*$" (sc-mail-fetch-field) nil t) + ("^$" (progn (bbdb/sc-default) + (list 'abort '(step . 0)))) + ("^[ \t]+" (sc-mail-append-field)) + (sc-mail-warn-if-non-rfc822-p (sc-mail-error-in-mail-field)) + (end (setq sc-mail-headers-end (point)))))) + +;; insert our hooks - call me from your Emacs initialization file +(defvar attribution) ;; dammit, supercite! +;;;###autoload +(defun bbdb-insinuate-sc () + "Call this function to hook BBDB into Supercite." + + (add-hook 'sc-post-hook 'bbdb/sc-set-attr) + (add-hook 'sc-attribs-postselect-hook + (function (lambda() + (setq bbdb/sc-last-attribution + (if sc-downcase-p + (downcase attribution) attribution)))))) + +(provide 'bbdb-sc) +;;; end of bbdb-sc.el diff --git a/xemacs-packages/lisp/bbdb/bbdb-sc.elc b/xemacs-packages/lisp/bbdb/bbdb-sc.elc new file mode 100644 index 0000000000000000000000000000000000000000..40d918bc6beee38adf74c0cbf5949cc3dd53755a GIT binary patch literal 6051 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 CK}A#m literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-snarf.el b/xemacs-packages/lisp/bbdb/bbdb-snarf.el new file mode 100644 index 00000000..ce4a4779 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-snarf.el @@ -0,0 +1,631 @@ +;;; bbdb-snarf.el -- convert free-form text to BBDB records + +;;; +;;; Copyright (C) 1997 by John Heidemann . +;;; $Id: bbdb-snarf.el,v 1.7 2005/07/24 15:22:58 waider Exp $ +;;; +;;; 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 version 1. +;;; +;;; 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;;; + +;;; +;;; bbdb-snarf is code to pick addresses, phones, and such out of a +;;; free-form paragraphs. Things are recognized by context (web pages +;;; start with http:// or www., for example). I wrote it because I +;;; despise fill-in-the-blank forms (a la bbdb-create). (if I wanted +;;; modes, I'd use vi :-). +;;; +;;; Eventually I'd like to be able to replace bbdb-mode with a free-form +;;; text mode where bbdb-snarf merges in any changes you make. +;;; I'm not there yet---merging is not good enough currently. +;;; Currently bbdb-snarf is good for pulling postal addresses +;;; from e-mail messages and converting other databases. +;;; + +(require 'bbdb) +(require 'bbdb-com) +(require 'rfc822) +(require 'mail-extr) + +(defconst bbdb-digit "[0-9]") +(defvar bbdb-snarf-phone-regexp + (concat + "\\(([2-9][0-9][0-9])[-. ]?\\|[2-9][0-9][0-9][-. ]\\)?" + "[0-9][0-9][0-9][-. ][0-9][0-9][0-9][0-9]" + "\\( *\\(x\\|ext\\.?\\) *[0-9]+\\)?" + ) + "regexp to match phones.") +(defvar bbdb-snarf-zip-regexp + (concat + "\\<" + bbdb-digit bbdb-digit bbdb-digit bbdb-digit bbdb-digit + "\\(-" bbdb-digit bbdb-digit bbdb-digit bbdb-digit "\\)?" + "\\>$") + "regexp matching zip.") + +(defcustom bbdb-snarf-web-prop 'www + "What property bbdb should use for the web, or nil to not detect web URLs." + :group 'bbdb + :type 'symbol) + +(defun bbdb-snarf-address-lines () + (let ((lines (bbdb-split (buffer-string) "\n"))) + (if (>= bbdb-file-format 5) nil + (while (< (length lines) 3) + (setq lines (append lines (list nil)))) + (if (> (length lines) 3) + (error "bbdb-snarf-address-lines: too many lines in address."))) + (delete-region (point-min) (point-max)) + lines)) + +(defun bbdb-snarf-make-address + (label address-lines city state zip country) + (if (>= bbdb-file-format 4) + (vector label address-lines city state zip country) + (if (>= bbdb-file-format 3) + (vector label address-lines city state zip) + (vector label + (nth 0 address-lines) + (nth 1 address-lines) + (nth 2 address-lines) + city state zip)))) + +(defun bbdb-snarf-prune-empty-lines () + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*\n" (point-max) t) + (replace-match ""))) + +(defun delete-and-return-region (begin end) + (prog1 + (buffer-substring begin end) + (delete-region begin end))) + +(defun bbdb-snarf-extract-label (default consume-p) + "Extract the label before the point, or return DEFAULT if no label. +If CONSUME-P is set, delete the text, if found." + (interactive "sDefault label: ") + (let ((end (point-marker))) + (skip-chars-backward " \t") + (if (not (= (point) (point-min))) + (forward-char -1)) + (if (looking-at ":") + (let* ((label-end (point)) + (label (delete-and-return-region + (progn (skip-chars-backward "^\n,;") (point)) + label-end))) + (delete-region (point) end) + label) + default))) + +(defun bbdb-snarf-parse-phone-number (phone) + "Fix the bogosity that is `bbdb-snarf-parse-phone-number'. +It doesn't always return a normalized phone number. +For (800) 555-1212 it returns a three element list." + (let ((try (bbdb-parse-phone-number phone))) + (if (= 3 (length try)) + (nconc try '(0))) + try)) + +;;;###autoload +(defun bbdb-snarf (where) + "snarf up a bbdb record WHERE the point is. +We assume things are line-broken and paragraph-bounded. +The name comes first and other fields (address, +phone, email, web pages) are recognized by context. + +Required context: + addresses end with \"City, State ZIP\" or \"City, State\" + phones match bbdb-snarf-phone-regexp + (currently US-style phones) + e-mail addresses have @'s in them + web sites are recognized by http:// or www. + +Address and phone context are currently US-specific; +patches to internationalize these assumptions are welcome. + +\\[bbdb-snarf] is similar to \\[bbdb-whois-sentinel], but less specialized." + (interactive "d") + (bbdb-snarf-region + (progn (goto-char where) (forward-paragraph -1) (point)) + (progn (forward-paragraph 1) (point)))) + +;;;###autoload +(defun bbdb-snarf-region (begin end) + "snarf up a bbdb record in the current region. See `bbdb-snarf' for +more details." + (interactive "r") + + (save-excursion + (let + ((buf (get-buffer-create " *BBDB snarf*")) + (text (buffer-substring-no-properties begin end)) + phones nets web city state zip name address-lines + address-vector notes) + (set-buffer buf) + (erase-buffer) + (insert text) + + ;; toss beginning and trailing space + (goto-char (point-min)) + (while (re-search-forward "^[ \t]+" (point-max) t) + (replace-match "")) + (goto-char (point-min)) + (while (re-search-forward "^\\s +$" (point-max) t) + (replace-match "")) + + ;; first, pick out phone numbers + (goto-char (point-min)) + (while (re-search-forward bbdb-snarf-phone-regexp (point-max) t) + (let (phone + (begin (match-beginning 0)) + (end (match-end 0))) + (goto-char begin) + (forward-char -1) + (if (looking-at "[0-9A-Za-z]") + (goto-char end);; not really phone + (setq phone (bbdb-snarf-parse-phone-number + (delete-and-return-region begin end)) + phones (append phones + (list (vconcat + (list (bbdb-snarf-extract-label + (bbdb-label-completion-default + 'phone) t)) + phone))))))) + + ;; next, web pages + (goto-char (point-min)) + (if (and bbdb-snarf-web-prop + (re-search-forward "\\(http://\\|www\.\\)[^ \t\n]+" + (point-max) t)) + (progn + (setq web (match-string 0) + notes (append notes (list (cons bbdb-snarf-web-prop web)))) + (replace-match ""))) + + ;; next e-mail + (goto-char (point-min)) + (while (re-search-forward "[^ \t\n<]+@[^ \t\n>]+" (point-max) t) + (setq nets (append nets (list (match-string 0)))) + (replace-match "")) + + (bbdb-snarf-prune-empty-lines) + + ;; name + (goto-char (point-min)) + ;; This check is horribly english-centric (I think) + (while (/= (char-syntax (char-after (point))) ?w) + (forward-line 1)) + (re-search-forward "\\(\\sw\\|[ -\.,]\\)*\\sw" nil t) + (setq name (match-string 0)) + (delete-region (match-beginning 0) (match-end 0)) + + ;; address + (goto-char (point-min)) + (cond + ;; city, state zip + ((re-search-forward bbdb-snarf-zip-regexp (point-max) t) + (save-excursion + (save-restriction + (let (mk) + (narrow-to-region (point-min) (match-end 0)) + (goto-char (point-max)) + ;; zip + (re-search-backward bbdb-snarf-zip-regexp (point-min) t) + (setq zip (bbdb-parse-zip-string (match-string 0))) + ;; state + (skip-chars-backward " \t") + (setq mk (point)) + (skip-chars-backward "^ \t,") + (setq state (buffer-substring (point) mk)) + ;; city + (skip-chars-backward " \t,") + (setq mk (point)) + (beginning-of-line) + (setq city (buffer-substring (point) mk)) + ;; toss it + (forward-char -1) + (delete-region (point) (point-max)) + ;; address lines + (goto-char (point-min)) + (setq address-lines (bbdb-snarf-address-lines) + address-vector (list (bbdb-snarf-make-address + (bbdb-label-completion-default + 'address) + address-lines + city + state + zip + "";; FIXME: snarf country + ))))))) + ;; try for just city, state + ((re-search-forward "^\\(.*\\), \\([A-Z][A-Za-z]\\)$" + (point-max) t) + (save-excursion + (save-restriction + (setq city (match-string 1) + state (match-string 2)) + (narrow-to-region (point-min) (match-end 0)) + (goto-char (point-min)) + (setq address-lines (bbdb-snarf-address-lines) + address-vector (list (bbdb-snarf-make-address + "address" + address-lines + city + state + 0 + "";; FIXME: snarf country + )))))) + (t + (setq address-lines '(nil nil nil) + address-vector nil))) + + ;; anything else -> notes + (bbdb-snarf-prune-empty-lines) + (if (/= (point-min) (point-max)) + (setq notes (append notes (list (cons 'notes (buffer-string)))))) + + ;; debug + ; (goto-char (point-max)) + ; (insert "\n\n" + ; "name: " name "\n" + ; "city: " city "\n" + ; "state: " state "\n" + ; "zip: " zip "\n") + (bbdb-merge-interactively name + nil + nets + address-vector + phones + notes)))) + + +; (setq bbdb-snarf-test-cases " +; +; another test person +; 1234 Gridley St. +; Los Angeles, CA 91342 +; 555-1212 +; test@person.net +; http://www.foo.bar/ +; other stuff about this person +; +; test person +; 1234 Gridley St. +; St. Los Angeles, CA 91342-1234 +; 555-1212 +; test@person.net +; +; x test person +; 1234 Gridley St. +; Los Angeles, California 91342-1234 +; 555-1212 +; test@person.net +; +; y test person +; 1234 Gridley St. +; Los Angeles, CA +; 555-1212 +; test@person.net +; " +; "some test cases") + + + +(defun bbdb-merge-interactively (name company nets addrs phones notes) + "Interactively add a new record; arguments same as \\[bbdb-create-internal]." + (let* + ((f-l-name (bbdb-divide-name name)) + (firstname (car f-l-name)) + (lastname (nth 1 f-l-name)) + (aka nil) + (new-record + (vector firstname lastname aka company phones addrs + (if (listp nets) nets (list nets)) notes + (make-vector bbdb-cache-length nil))) + (old-record (bbdb-search-simple name nets))) + (if old-record + (progn + (setq new-record (bbdb-merge-internally old-record new-record)) + (bbdb-delete-record-internal old-record))) + ;; create new record + (bbdb-invoke-hook 'bbdb-create-hook new-record) + (bbdb-change-record new-record t) + (bbdb-hash-record new-record) + (bbdb-display-records (list new-record)))) + +(defun bbdb-merge-internally (old-record new-record) + "Merge two records. NEW-RECORDS wins over OLD in cases of ties." + (if (and (null (bbdb-record-firstname new-record)) + (bbdb-record-firstname old-record)) + (bbdb-record-set-firstname new-record (bbdb-record-firstname old-record))) + (if (and (null (bbdb-record-lastname new-record)) + (bbdb-record-lastname old-record)) + (bbdb-record-set-lastname new-record (bbdb-record-lastname old-record))) + (if (and (null (bbdb-record-company new-record)) + (bbdb-record-company old-record)) + (bbdb-record-set-company new-record (bbdb-record-company old-record))) + ;; nets + (let ((old-nets (bbdb-record-net old-record)) + (new-nets (bbdb-record-net new-record))) + (while old-nets + (if (not (member (car old-nets) new-nets)) + (setq new-nets (append new-nets (list (car old-nets))))) + (setq old-nets (cdr old-nets))) + (bbdb-record-set-net new-record new-nets)) + ;; addrs + (let ((old-addresses (bbdb-record-addresses old-record)) + (new-addresses (bbdb-record-addresses new-record))) + (while old-addresses + (if (not (member (car old-addresses) new-addresses)) + (setq new-addresses (append new-addresses (list (car old-addresses))))) + (setq old-addresses (cdr old-addresses))) + (bbdb-record-set-addresses new-record new-addresses)) + ;; phones + (let ((old-phones (bbdb-record-phones old-record)) + (new-phones (bbdb-record-phones new-record))) + (while old-phones + (if (not (member (car old-phones) new-phones)) + (setq new-phones (append new-phones (list (car old-phones))))) + (setq old-phones (cdr old-phones))) + (bbdb-record-set-phones new-record new-phones)) + ;; notes + (let ((old-notes (bbdb-record-raw-notes old-record)) + (new-notes (bbdb-record-raw-notes new-record))) + (while old-notes + (if (not (member (car old-notes) new-notes)) + (setq new-notes (append new-notes (list (car old-notes))))) + (setq old-notes (cdr old-notes))) + (bbdb-record-set-raw-notes new-record new-notes)) + ;; return + new-record) + +;;---------------------------------------------------------------------------- +(eval-and-compile + (if (fboundp 'replace-in-string) + (fset 'bbdb-replace-in-string 'replace-in-string) + (if (fboundp 'replace-regexp-in-string) ; defined in e21 + (fset 'bbdb-replace-regexp-in-string 'replace-regexp-in-string) + ;; actually this is `dired-replace-in-string' slightly modified + ;; We're not defining the whole thing, just enough for our purposes. + (defun bbdb-replace-regexp-in-string (regexp newtext string &optional + fixedcase literal) + ;; Replace REGEXP with NEWTEXT everywhere in STRING and return result. + ;; NEWTEXT is taken literally---no \\DIGIT escapes will be recognized. + (let ((result "") (start 0) mb me) + (while (string-match regexp string start) + (setq mb (match-beginning 0) + me (match-end 0) + result (concat result (substring string start mb) newtext) + start me)) + (concat result (substring string start))))) + (defun bbdb-replace-in-string (string regexp newtext &optional literal) + (bbdb-replace-regexp-in-string regexp newtext string nil literal)))) + +(defcustom bbdb-extract-address-components-func + 'bbdb-rfc822-addresses + "Function called to parse one or more email addresses. +See bbdb-extract-address-components for an example." + :group 'bbdb-noticing-records + :type 'function) + +(defcustom bbdb-extract-address-component-regexps + '( +;; This was part of Dave Love's patch. Alas, it appears to break the +;; very thing it is supposed to handle, viz. unwrapping "Last, First" +;; into "First Last". Thusly, commented out for now. The unwrapping +;; seems to work fine without it? +;; +;; "surname, firstname"

from Outlookers +;; ("\"\\([^\"]*\\)\"\\s-*<\\([^>]+\\)>" +;; (bbdb-clean-username (match-string 1 adstring)) 2) + ;; "name"
+ ("\"\\([^\"]*\\)\"\\s-*<\\([^>]+\\)>" + (car (mail-extract-address-components + (concat "\"" (match-string 1 adstring) "\""))) + 2) + ;; name
+ ("\\([^<>,\t][^<>,]+[^<>, \t]\\)\\s-*<\\([^>]+\\)>" + 1 2) + ;;
+ ("<\\([^>,]+\\)>" nil 1) + ;; address (name) + ("\\(\\b[^<\",()]+\\b\\)\\s-*(\\([^)]+\\))" + (car (mail-extract-address-components + (concat "\"" (match-string 2 adstring) "\""))) + 1) + ;; firstname.lastname@host + ("\\b\\(\\([^@ \t\n.]+\\.[^@ \t\n.]+\\)@[^@ \t\n]+\\)\\b" + (car (mail-extract-address-components + (concat "\"" (match-string 2 adstring) "\""))) + 1) + ;; user@host + ("\\b\\(\\([^@ \t\n]+\\)@[^@ \t\n]+\\)\\b" + nil 1) + ;; localaddress + ("\\b\\([^@ \t\n]+\\)\\b" + nil 1) + ) + "*List of regexps matching headers. +Each list element should have the form (REGEXP FULLNAME ADDRESS), where +REGEXP matches the address while the actual address components should +be a parenthesized expression. + +FULLNAME is a default string for addresses without full name or a +number denoting parenthesized expression. +ADDRESS is a number denoting the parenthesized expression matching the +address. + +If FULLNAME or ADDRESS is a list it will be evaluated to return a +string or nil. If its a function it will be called with the remaining +address-string as argument." + :group 'bbdb-noticing-records + :type 'list) + +(defcustom bbdb-extract-address-component-ignore-regexp + "\\(\\(undisclosed\\|unlisted\\)[^,]*recipients\\)\\|no To-header on input" + "*A regexp matching addresses which should be ignored." + :group 'bbdb-noticing-records + :type 'string) + +(defcustom bbdb-extract-address-component-handler 'message + "*Specifies how `bbdb-extract-address-components' reports errors. + +A value of nil means ignore unparsable stuff and 'warn will report +a warning, 'message will report a message in the minibuffer and all +other value will fire a error. + +When set to a function it will be called with the remaining string in +order to extract the address components and return the rest and the +components as list or to do what ever it wants, e.g. send a complain +to the author ... + +To skip known unparseable stuff you rather should set the variable +`bbdb-extract-address-component-ignore-regexp' instead of disabling +this handler." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Ignore problems." + nil) + (const :tag "Warn about parsing problems." + 'warn) + (const :tag "Show a message about parsing problems." + 'message) + (function :tag "A user defined handler"))) + +;;;###autoload +(defun bbdb-extract-address-components (adstring &optional ignore-errors) + "Return a list of address components found in ADSTRING. +If extracting fails one probably has to adjust the variable +`bbdb-extract-address-component-regexps'." + (let ((case-fold-search t) + (fnadlist nil) + adcom-regexp + nomatch) + + ;; Do some string cleanup and trimming + (setq adstring (bbdb-replace-in-string adstring "[\n\t]" " ")) + (setq adstring (bbdb-replace-in-string adstring " " " ")) + (setq adstring (bbdb-replace-in-string adstring "^ +" "")) + + ;; scan the string + (while (not (string= "" adstring)) + (setq adcom-regexp bbdb-extract-address-component-regexps + nomatch t) + (while adcom-regexp + (let ((regexp (caar adcom-regexp)) + (fn (car (cdar adcom-regexp))) + (ad (cadr (cdar adcom-regexp)))) + (cond ((string-match + (concat "^[^,]*\\(" + bbdb-extract-address-component-ignore-regexp + "\\)[^,]*\\(,\\|$\\)") + adstring) + (setq adstring (substring adstring (match-end 0)) + adcom-regexp nil + nomatch nil)) + ((string-match (concat "^\\s-*" regexp "\\s-*\\(,\\|$\\)") + adstring) + (add-to-list 'fnadlist + (list (let ((n + (cond ((numberp fn) + (match-string fn adstring)) + ((listp fn) + (save-match-data (eval fn))) + ((functionp fn) + (save-match-data + (funcall fn adstring))) + (t fn)))) + (if (string= n "") + nil + n)) + (let ((a + (cond ((numberp ad) + (match-string ad adstring)) + ((listp ad) + (save-match-data (eval ad))) + ((functionp ad) + (save-match-data + (funcall ad adstring))) + (t ad)))) + (if (string= a "") + nil + a)))) +; (save-match-data +; (message "%S Match on %S to\n\t%S" +; regexp adstring fnadlist)) + (setq adstring (substring adstring (match-end 0)) + adcom-regexp nil + nomatch nil))) + (setq adcom-regexp (cdr adcom-regexp)))) + + ;; Now handle problems + (if (and nomatch (not ignore-errors)) + (cond ((equal bbdb-extract-address-component-handler nil)) + ((equal bbdb-extract-address-component-handler 'warn) + (bbdb-warn "Cannot extract an address component at \"%s\". +See `bbdb-extract-address-component-handler' for more information." + adstring)) + ((equal bbdb-extract-address-component-handler 'message) + (message "Cannot extract an address component at \"%s\"." + adstring)) + ((functionp bbdb-extract-address-component-handler) + (let ((result + (funcall bbdb-extract-address-component-handler + adstring))) + (if (and (listp result) (= 3 (length result))) + (progn (add-to-list 'fnadlist (cdr result)) + (setq adstring (car result) + nomatch nil))))) + (t + (error "Cannot extract an address component at \"%30s\"" + adstring)))) + + ;; ignore the bad junk + (if nomatch + (if (string-match "^[^,]*," adstring) + (setq adstring (substring adstring (match-end 0))) + (setq adstring "")))) + + (delete '(nil nil) (nreverse fnadlist)))) + +;;; alternative name parser +;;;###autoload +(defun bbdb-rfc822-addresses ( addrline &optional ignore-errors) + "Split ADDRLINE into a list of parsed addresses. + +You can't do this with rfc822.el in any sort of useful way because it discards +the comments. You can't do this with mail-extr.el because the multiple address +parsing in GNU Emacs appears to be broken beyond belief, and the XEmacs +version doesn't support multiple addresses." + (let (addrs (start 0)) + (setq addrline (concat addrline ",")) ;; kludge, to make parsing easier + ;; Addresses are separated by commas. This is probably the worst + ;; possible way to do this, but it does cut down on the amount of + ;; coding effort I have to duplicate. Basically, we split on + ;; commas, and then try and parse what we've found. Pathologically + ;; bad address lines will break this. + (while (string-match "\\([^,]+\\)," addrline start) + (let* ((thisaddr (substring addrline 0 (match-end 1))) + (comma (match-end 0)) ;; rfc822-addresses trashes match-data + (parsed (rfc822-addresses thisaddr))) + (if (string-match "(" (or (car parsed) "")) ;; rfc822 didn't like it. + (setq start comma) + (setq addrs + (append addrs (list + (mail-extract-address-components + thisaddr))) + ;; throw away what we just parsed + addrline (substring addrline comma) + start 0)))) + addrs)) + +(provide 'bbdb-snarf) diff --git a/xemacs-packages/lisp/bbdb/bbdb-snarf.elc b/xemacs-packages/lisp/bbdb/bbdb-snarf.elc new file mode 100644 index 0000000000000000000000000000000000000000..60bcb644e285571d4252076377e9f2e4afb9fad8 GIT binary patch literal 11932 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. +;;; Invoking BBDB from another process, via `gnudoit'. +;;; See the file bbdb.texinfo for documentation. +;;; +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-srv.el,v 1.8 2005/07/24 15:22:58 waider Exp $ + +;;; This requires the `gnuserv' and `itimer' packages. +;;; +;;; To use: +;;; +;;; First, do `(gnuserv-start)' to initialize the emacs server process. +;;; If you don't know what this does, see the doc for gnuserv.el. +;;; +;;; Then, an external process may invoke `gnudoit' in the following way: +;;; +;;; gnudoit '(bbdb-server "...all message headers..")' +;;; +;;; The bbdb-srv.perl program is a good choice for this; it takes a header +;;; block on stdin, and converts them to a lisp string, taking care to +;;; "sanitize" them so that hostile data can't take over the executing shell. +;;; +;;; The string should be a validly-formatted-and-quoted lisp string, and +;;; should contain multiple lines, which are the headers of the message for +;;; which a record should be displayed. It should contain at least a "From:" +;;; header, or nothing will be displayed, but it should contain as many headers +;;; as your various BBDB hooks might want access to. +;;; +;;; Records will not be displayed until no record has been requested for +;;; `bbdb/srv-display-delay' seconds (default 2.) This is to prevent rapid +;;; display of records from queueing up and swamping the emacs server process. +;;; +;;; Note that in order for this to build, itimer.el and gnuserv.el must be in +;;; the build-path. The easiest way to achieve this is to set OTHERDIR to point +;;; to the directory/ies they're in. + +;;; A trivial application of this is the shell command: +;;; +;;; echo 'From: Jamie Zawinski ' | bbdb-srv.perl +;;; +;;; which will cause the corresponding record to be displayed. +;;; A more interesting application of this is: +;;; +;;; setenv NS_MSG_DISPLAY_HOOK bbdb-srv.perl +;;; +;;; which will hook BBDB up to Mozilla (Unix Netscape Mail and Netscape News +;;; versions 3.0b2 and later only.) + +(require 'bbdb) +(require 'bbdb-com) +(require 'bbdb-hooks) + + +(eval-when-compile + (require 'mail-utils) ;; for mail-strip-quoted-names + (require 'bbdb-gui) ;; for extents macros + (if (featurep 'xemacs) + () + (fset 'set-keymap-name 'ignore) + (fset 'frame-lowest-window 'ignore))) + +;; newer version of gnuserv requires gnuserv-compat when using FSF emacs +;; but you might be using an older version, and we can't tell until you +;; crash it... +(or (fboundp 'define-obsolete-variable-alias) + (if (locate-library "gnuserv-compat") + (require 'gnuserv-compat))) +(require 'gnuserv) +(require 'itimer) + +(defcustom bbdb/srv-auto-create-p nil + "*Like `bbdb/news-auto-create-p' and `bbdb/mail-auto-create-p', +but for the case where the record is being displayed by some external +process via the `gnudoit' mechanism. + +If this is t, then records will automatically be created; if this is a +function name or lambda, then it is called with no arguments to decide +whether an entry should be automatically created. You can use this to, +for example, create or not create messages which have a particular subject. + +`bbdb/srv-auto-create-mail-news-dispatcher' is a good value for this -- +that function will try to decide if this is a mail message or a news +message, and then run either `bbdb/news-auto-create-p' or +`bbdb/mail-auto-create-p' as appropriate." + :group 'bbdb-utilities-server + :type '(choice (const :tag "Don't automatically create records" nil) + (const :tag "Automatically create records" t) + (sexp :tag "Use function to determine record creation" + bbdb/srv-auto-create-mail-news-dispatcher))) + +(defcustom bbdb/srv-display-delay 2 + "*How long (in seconds) we must be idle before displaying a record." + :group 'bbdb-utilities-server + :type 'integer) + +(defvar bbdb/srv-pending-headers nil) +(defvar bbdb/srv-pending-map + (and (fboundp 'bbdb-set-extent-property) + (condition-case nil + (let ((m (make-sparse-keymap))) + (set-keymap-name m 'bbdb/srv-pending-map) + (define-key m 'button1 'bbdb/srv-pending-add) + m) + (error nil)))) + +(defun bbdb/srv-handle-headers (headers &optional create-p) + "Display (or create) the BBDB entry corresponding to the message headers. +HEADERS should be a string containing an RFC822 header block; at least a +\"From:\" header should be provided, but others will be made available to +the various hooks (like `bbdb-notice-hook' and `bbdb/news-auto-create-p')." + (let ((buf "*bbdb-tmp*") + (record nil) + (bbdb-force-dialog-boxes t) ; affects bbdb-y-or-n-p + from) + (save-excursion + (set-buffer (or (get-buffer buf) + (progn + (setq buf (get-buffer-create buf)) + (set-buffer buf) + (buffer-disable-undo buf) + buf))) + (erase-buffer) + (insert headers "\n\n") + (setq from (mail-fetch-field "from")) + (if (or (null from) + (string-match (bbdb-user-mail-names) + (mail-strip-quoted-names from))) + ;; if logged-in user sent this, use recipients. + (setq from (or (mail-fetch-field "to") from))) + (if from + (setq record + (bbdb-annotate-message-sender from t + (or create-p + (bbdb-invoke-hook-for-value + bbdb/srv-auto-create-p)) + nil)))) + (let ((w (get-buffer-window bbdb-buffer-name))) + (if w + nil + (setq w (selected-window)) + (unwind-protect + (progn + (if (fboundp 'frame-lowest-window) + (select-window (frame-lowest-window))) + (bbdb-pop-up-bbdb-buffer)) + (select-window w)) + (setq w (get-buffer-window bbdb-buffer-name)) + (if (fboundp 'set-window-dedicated-p) + (set-window-dedicated-p w bbdb-buffer-name)))) + (cond (record + (let ((bbdb-gag-messages t) + (bbdb-use-pop-up nil) + (bbdb-electric-p nil) + (b (current-buffer))) + (save-window-excursion ;; needed to get around XEmacs 19.15 bug? + (bbdb-display-records (list record)) bbdb-pop-up-display-layout) + (set-buffer b))) + ((and from (not create-p) bbdb/srv-pending-map) + (setq bbdb/srv-pending-headers headers) + (save-excursion + (set-buffer bbdb-buffer-name) + (let ((buffer-read-only nil)) + (erase-buffer) + (insert "\t\t\t") + (let ((p (point)) + e) + (insert from) + (setq e (bbdb-make-extent p (point))) + (bbdb-set-extent-face e 'bold) + (bbdb-set-extent-property e 'highlight t) + (bbdb-set-extent-property e 'keymap bbdb/srv-pending-map) + ) + (insert "\n\n\t\t\tClick to add to BBDB.") + )))))) + +(defun bbdb/srv-pending-add () + (interactive "@") + (or bbdb/srv-pending-headers (error "lost headers?")) + (bbdb/srv-handle-headers bbdb/srv-pending-headers t)) + + +(defvar bbdb/srv-itimer-arg nil) +(defun bbdb/srv-itimer () + "Used as a timer function by bbdb/srv-handle-headers-with-delay. +This invokes bbdb/srv-handle-headers with bbdb/srv-itimer-arg. +We do it this way instead of by using a lambda to start-itimer so that +we cons less." + (defvar current-itimer) + (if current-itimer (delete-itimer current-itimer)) + (if bbdb/srv-itimer-arg + (bbdb/srv-handle-headers + (prog1 bbdb/srv-itimer-arg + (setq bbdb/srv-itimer-arg nil))))) + +;;;###autoload +(defun bbdb/srv-handle-headers-with-delay (headers) + "Just like bbdb/srv-handle-headers, but only updates every few seconds. +This is so that trying to display many records in succession won't queue them +up, but will end up only displaying a record when no displays have been +requested for a couple of seconds." + (let* ((name "bbdb-srv") + (itimer (get-itimer name))) + (setq bbdb/srv-itimer-arg headers) + (if itimer + ;; It hasn't gone off yet; just change what it's argument will be. + nil + ;; else, start the timer going again. + (start-itimer name 'bbdb/srv-itimer bbdb/srv-display-delay nil)) + nil)) + +;;;###autoload +(defalias 'bbdb-srv 'bbdb/srv-handle-headers-with-delay) + +(autoload 'bbdb-header-start "bbdb-hooks") + +;;;###autoload +(defun bbdb/srv-auto-create-mail-news-dispatcher () + "For use as the value of bbdb/srv-auto-create-p. +This will try to decide if this is a mail message or a news message, and then +run either bbdb/news-auto-create-p or bbdb/mail-auto-create-p as appropriate. +\(The heuristic is that news messages never have a Status or X-Mozilla-Status +header; and that mail messages never have Path headers.)" + (let (mail-p) + (save-excursion + (let ((start (bbdb-header-start))) + (set-buffer (marker-buffer start)) + (setq mail-p + (cond ((progn (goto-char start) + (bbdb-extract-field-value "Status")) + t) + ((progn (goto-char start) + (bbdb-extract-field-value "X-Mozilla-Status")) + t) + ((progn (goto-char start) + (bbdb-extract-field-value "Path")) + nil) + (t t))))) ; can't tell -- guess mail. + (bbdb-invoke-hook-for-value + (if mail-p bbdb/mail-auto-create-p bbdb/news-auto-create-p)))) + + +;; For caller-id stuff +;;;###autoload +(defun bbdb-srv-add-phone (phone-string &optional description record) + (let ((phone (make-vector (if bbdb-north-american-phone-numbers-p + bbdb-phone-length + 2) + nil))) + (setq record (if (stringp record) + (or (bbdb-search-simple record "") + (bbdb-create-internal record nil nil nil nil nil)) + (bbdb-completing-read-record + (format "Add %s to: " phone-string)))) + (if (= 2 (length phone)) + (aset phone 1 phone-string) + (let ((newp (bbdb-parse-phone-number phone-string))) + (bbdb-phone-set-area phone (nth 0 newp)) + (bbdb-phone-set-exchange phone (nth 1 newp)) + (bbdb-phone-set-suffix phone (nth 2 newp)) + (bbdb-phone-set-extension phone (or (nth 3 newp) 0)))) + (bbdb-phone-set-location phone + (or description + (read-string "Phone number description: " + "cid"))) + (bbdb-record-set-phones record + (nconc (bbdb-record-phones record) (list phone))) + (bbdb-change-record record nil) + (bbdb-display-records (list record)) + record)) + +(provide 'bbdb-srv) diff --git a/xemacs-packages/lisp/bbdb/bbdb-srv.elc b/xemacs-packages/lisp/bbdb/bbdb-srv.elc new file mode 100644 index 0000000000000000000000000000000000000000..e5d56a9b2db359b658d5c0bb2b54f6eb12a1149c GIT binary patch literal 6882 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-vm.el b/xemacs-packages/lisp/bbdb/bbdb-vm.el new file mode 100644 index 00000000..52fc2fb1 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-vm.el @@ -0,0 +1,432 @@ +;;; -*- Mode:Emacs-Lisp -*- + +;;; This file is the part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992, 1993 Jamie Zawinski . +;;; Interface to VM (View Mail) 5.31 or greater. See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-vm.el,v 1.7 2005/07/24 15:22:58 waider Exp $ +;; + +(eval-and-compile + (require 'cl) + (require 'bbdb) + (require 'bbdb-com) + (require 'bbdb-snarf) + (require 'vm-autoload) + (require 'vm) + + (if (not (fboundp 'vm-record-and-change-message-pointer)) + (load-library "vm-motion")) + (if (not (fboundp 'vm-su-from)) + (load-library "vm-summary")) + (or (boundp 'vm-mode-map) + (load-library "vm-vars"))) + +(defun bbdb/vm-get-header-content (header-field msg) + (let ((content (vm-get-header-contents msg (concat header-field ":")))) + (if content + (vm-decode-mime-encoded-words-in-string content)))) + +(defcustom bbdb/vm-update-records-mode + '(if (vm-new-flag msg) 'annotating 'searching) + "Controls how `bbdb/vm-update-records' processes email addresses. +Set this to an expression which evaluates either to 'searching or +'annotating. When set to 'annotating email addresses will be fed to +`bbdb-annotate-message-sender' in order to update existing records or create +new ones. A value of 'searching will search just for existing records having +the right net. + +The default is to annotate only new messages." + :group 'bbdb-mua-specific-vm + :type '(choice (const :tag "annotating all messages" + annotating) + (const :tag "annotating no messages" + searching) + (const :tag "annotating only new messages" + (if (vm-new-flag msg) 'annotating 'searching)) + (sexp :tag "user defined"))) + +;;;###autoload +(defun bbdb/vm-update-record (&optional offer-to-create) + (let* ((bbdb-get-only-first-address-p t) + (records (bbdb/vm-update-records offer-to-create))) + (if records (car records) nil))) + +;;;###autoload +(defun bbdb/vm-update-records (&optional offer-to-create) + "Returns the records corresponding to the current VM message, +creating or modifying them as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil or if OFFER-TO-CREATE is true, and +the user confirms the creation. + +The variable `bbdb/vm-update-records-mode' controls what actions +are performed and it might override `bbdb-update-records-mode'. + +When hitting C-g once you will not be asked anymore for new people listed +in this message, but it will search only for existing records. When hitting +C-g again it will stop scanning." + (vm-select-folder-buffer) + (vm-check-for-killed-summary) + (vm-error-if-folder-empty) + (let ((msg (car vm-message-pointer)) + (enable-local-variables t) ; ...or vm bind this to nil. + (inhibit-quit nil) ; vm better not bind this to t! + (bbdb/vm-offer-to-create offer-to-create) + cache records) + + ;; ignore cache if we may be creating a record, since the cache + ;; may otherwise tell us that the user didn't want a record for + ;; this person. + (if (not bbdb/vm-offer-to-create) + (setq cache (and msg (bbdb-message-cache-lookup msg)))) + + (if cache + (setq records (if bbdb-get-only-first-address-p + (list (car cache)) + cache)) + + (let ((bbdb-update-records-mode (or bbdb/vm-update-records-mode + bbdb-update-records-mode))) + (setq records (bbdb-update-records + (bbdb-get-addresses bbdb-get-only-first-address-p + vm-summary-uninteresting-senders + 'bbdb/vm-get-header-content + (vm-real-message-of msg)) + bbdb/mail-auto-create-p + offer-to-create)) + + (bbdb-encache-message msg records))) + records)) + +;;;###autoload +(defun bbdb/vm-annotate-sender (string &optional replace) + "Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message. If REPLACE is non-nil, +replace the existing notes entry (if any)." + (interactive + (list (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.") + (read-string "Comments: ")))) + (vm-follow-summary-cursor) + (let ((record (or (bbdb/vm-update-record t) (error "unperson")))) + (bbdb-annotate-notes record string 'notes replace))) + +(defun bbdb/vm-edit-notes (&optional arg) + "Edit the notes field or (with a prefix arg) a user-defined field +of the BBDB record corresponding to the sender of this message." + (interactive "P") + (vm-follow-summary-cursor) + (let ((record (or (bbdb/vm-update-record t) (error "unperson")))) + (bbdb-display-records (list record)) + (if arg + (bbdb-record-edit-property record nil t) + (bbdb-record-edit-notes record t)))) + +;;;###autoload +(defun bbdb/vm-show-records (&optional address-class) + "Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." + (interactive) + (vm-follow-summary-cursor) + (let ((bbdb-get-addresses-headers + (if address-class + (list (assoc address-class bbdb-get-addresses-headers)) + bbdb-get-addresses-headers)) + (bbdb/vm-update-records-mode 'annotating) + (bbdb-message-cache nil) + ;; should we move this to bbdb/vm-show-sender? + (bbdb-user-mail-names nil) + (vm-summary-uninteresting-senders nil) + records) + (setq records (bbdb/vm-update-records t)) + (if records + (bbdb-display-records records) + (bbdb-undisplay-records)) + records)) + +;;;###autoload +(defun bbdb/vm-show-all-recipients () + "Show all recipients of this message. Counterpart to `bbdb/vm-show-sender'." + (interactive) + (let ((bbdb-get-only-first-address-p nil)) + (bbdb/vm-show-records 'recipients))) + +;;;###autoload +(defun bbdb/vm-show-sender (&optional show-recipients) + "Display the contents of the BBDB for the senders of this message. +With a prefix argument show the recipients instead, +with two prefix arguments show all records. +This buffer will be in `bbdb-mode', with associated keybindings." + (interactive "p") + (cond ((= 4 show-recipients) + (bbdb/vm-show-all-recipients)) + ((= 16 show-recipients) + (let ((bbdb-get-only-first-address-p nil)) + (bbdb/vm-show-records))) + (t + (if (null (bbdb/vm-show-records 'authors)) + (bbdb/vm-show-all-recipients))))) + +(defun bbdb/vm-pop-up-bbdb-buffer (&optional offer-to-create) + "Make the *BBDB* buffer be displayed along with the VM window(s). +Displays the records corresponding to the sender respectively +recipients of the current message. +See `bbdb/vm-get-addresses-headers' and 'bbdb-get-only-first-address-p' for +configuration of what is being displayed." + (save-excursion + (let ((bbdb-gag-messages t) + (bbdb-electric-p nil) + (records (bbdb/vm-update-records offer-to-create)) + (bbdb-buffer-name bbdb-buffer-name)) + + (when (and bbdb-use-pop-up records) + (bbdb-pop-up-bbdb-buffer + (function (lambda (w) + (let ((b (current-buffer))) + (set-buffer (window-buffer w)) + (prog1 (eq major-mode 'vm-mode) + (set-buffer b)))))) + + ;; Always update the records; if there are no records, empty the + ;; BBDB window. This should be generic, not VM-specific. + (bbdb-display-records records bbdb-pop-up-display-layout)) + + (when (not records) + (bbdb-undisplay-records) + (if (get-buffer-window bbdb-buffer-name) + (delete-window (get-buffer-window bbdb-buffer-name))))))) + + +;; By Alastair Burt +;; vm 5.40 and newer support a new summary format, %U, to call +;; a user-provided function. Use "%-17.17UB" instead of "%-17.17F" to +;; have your VM summary buffers display BBDB's idea of the sender's full +;; name instead of the name (or lack thereof) in the message itself. + +(defun vm-summary-function-B (m &optional to-p) + "Given a VM message returns the BBDB name of the sender. +Respects vm-summary-uninteresting-senders." + (if (and vm-summary-uninteresting-senders (not to-p)) + (let ((case-fold-search nil)) + (if (string-match vm-summary-uninteresting-senders (vm-su-from m)) + (concat vm-summary-uninteresting-senders-arrow + (vm-summary-function-B m t)) + (or (bbdb/vm-alternate-full-name (vm-su-from m)) + (vm-su-full-name m)))) + (or (bbdb/vm-alternate-full-name (if to-p (vm-su-to m) (vm-su-from m))) + (vm-decode-mime-encoded-words-in-string + (if to-p (vm-su-to-names m) (vm-su-full-name m)))))) + +(defun bbdb/vm-alternate-full-name (address) + (if address + (let ((entry (bbdb-search-simple + nil + (if (and address bbdb-canonicalize-net-hook) + (bbdb-canonicalize-address address) + address)))) + (if entry + (or (bbdb-record-getprop entry 'mail-name) + (bbdb-record-name entry)))))) + + +;; From: Mark Thomas +;; Subject: auto-folder-alist from bbdb + +;;;###autoload +(defcustom bbdb/vm-set-auto-folder-alist-field 'vm-folder + "*The field which `bbdb/vm-set-auto-folder-alist' searches for." + :group 'bbdb-mua-specific-vm + :type 'symbol) + +;;;###autoload +(defcustom bbdb/vm-set-auto-folder-alist-headers '("From:" "To:" "CC:") + "*The headers used by `bbdb/vm-set-auto-folder-alist'. +The order in this list is the order how matching will be performed!" + :group 'bbdb-mua-specific-vm + :type '(repeat (string :tag "header name"))) + +;;;###autoload +(defun bbdb/vm-set-auto-folder-alist () + "Create a `vm-auto-folder-alist' according to the records in the bbdb. +For each record that has a 'vm-folder' attribute, add an +element (email-regexp . folder) to the `vm-auto-folder-alist'. + +The element gets added to the 'element-name' sublist of the +`vm-auto-folder-alist'. + +The car of the element consists of all the email addresses for the +bbdb record concatenated with OR; the cdr is the value of the +vm-folder attribute. + +If the first character of vm-folders value is a quote ' it will be +parsed as lisp expression and is evaluated to return a folder name, +e.g. define you own function `my-folder-name' and set it to + '(my-folder-name)" + (interactive) + (let* (;; we add the email-address/vm-folder-name pair to this + ;; sublist of the vm-auto-folder-alist variable + (headers (reverse bbdb/vm-set-auto-folder-alist-headers)) + header + ;; grab the folder list from the vm-auto-folder-alist + folder-list + ;; the raw-notes and vm-folder attributes of the current bbdb + ;; record + notes-field folder + ;; a regexp matching all the email addresses from the bbdb + ;; record + email-regexp + ;; + records) + + (setq records + (delete + nil + (mapcar (lambda (r) + (let ((notes (bbdb-record-raw-notes r))) + (if (and notes + (assq bbdb/vm-set-auto-folder-alist-field + notes)) + r + nil))) + (bbdb-records)))) + + (while headers + (setq header (car headers) headers (cdr headers)) + ;; create the folder-list in vm-auto-folder-alist if it doesn't exist + (setq folder-list (assoc header vm-auto-folder-alist)) + (unless folder-list + (setq vm-auto-folder-alist (cons (list header) + vm-auto-folder-alist) + folder-list (assoc header vm-auto-folder-alist))) + (mapcar + (lambda (r) + (setq notes-field (bbdb-record-raw-notes r)) + (when (and (listp notes-field) + (setq folder (cdr (assq bbdb/vm-set-auto-folder-alist-field + notes-field)))) + ;; quote all the email addresses for the record and join them + ;; with OR + (setq email-regexp (regexp-opt (bbdb-record-net r))) + (unless (or (zerop (length email-regexp)) + (assoc email-regexp folder-list)) + ;; be careful: nconc modifies the list in place + (if (equal (elt folder 0) ?\') + (setq folder (read (substring folder 1)))) + (nconc folder-list (list (cons email-regexp folder)))))) + records)))) + + +;;; bbdb/vm-auto-add-label +;;; Howard Melman, contributed Jun 16 2000 +(defcustom bbdb/vm-auto-add-label-list nil + "*List used by `bbdb/vm-auto-add-label' to automatically label messages. +Each element in the list is either a string or a list of two strings. +If a single string then it is used as both the field value to check for +and the label to apply to the message. If a list of two strings, the first +is the field value to search for and the second is the label to apply." + :group 'bbdb-mua-specific-vm + :type 'list) + +(defcustom bbdb/vm-auto-add-label-field bbdb-define-all-aliases-field + "*Fields used by `bbdb/vm-auto-add-label' to automatically label messages. +Value is either a single symbol or a list of symbols of bbdb fields that +`bbdb/vm-auto-add-label' uses to check for labels to apply to messages. +Defaults to `bbdb-define-all-aliases-field' which is typically `mail-alias'." + :group 'bbdb-mua-specific-vm + :type '(choice symbol list)) + +(defun bbdb/vm-auto-add-label (record) + "Automatically add labels to messages based on the mail-alias field. +Add this to `bbdb-notice-hook' and if using VM each message that bbdb +notices will be checked. If the sender has a value in the +bbdb/vm-auto-add-label-field in their BBDB record that +matches a value in `bbdb/vm-auto-add-label-list' then a VM +label will be added to the message. + +This works great when `bbdb-user-mail-names' is set. As a result +mail that you send to people (and copy yourself on) is labeled as well. + +This is how you hook it in. +;; (add-hook 'bbdb-notice-hook 'bbdb/vm-auto-add-label) +" + (let (field aliases sep) + (and (eq major-mode 'vm-mode) + (mapcar #'(lambda(x) + (and + (setq field (bbdb-record-getprop record x)) + (setq sep (or (get x 'field-separator) ",")) + (setq aliases (append aliases (bbdb-split field sep))))) + (cond ((listp bbdb/vm-auto-add-label-field) + bbdb/vm-auto-add-label-field) + ((symbolp bbdb/vm-auto-add-label-field) + (list bbdb/vm-auto-add-label-field)) + (t (error "Bad value for bbdb/vm-auto-add-label-field")) + )) + (vm-add-message-labels + (mapconcat #'(lambda (l) + (cond ((stringp l) + (if (member l aliases) + l)) + ((and (consp l) + (stringp (car l)) + (stringp (cdr l))) + (if (member (car l) aliases) + (cdr l))) + (t + (error "Malformed bbdb/vm-auto-add-label-list") + ))) + bbdb/vm-auto-add-label-list + " ") + 1)))) + + +;;; Automatically add a record for replies. +;;; Contributed by Robert Fenk, 27 Oct 2000. It only took me 8 months to put +;;; it in the source... +;;; +;;; (add-hook 'vm-reply-hook 'bbdb/vm-force-create) to enable it. You could +;;; presumably hook it elsewhere as well. +(defun bbdb/vm-force-create () + "Force automatic adding of a bbdb entry for current message." + (interactive) + (let ((bbdb/mail-auto-create-p t) + (bbdb-message-caching-enabled nil)) + (save-excursion + (vm-select-folder-buffer) + (bbdb/vm-pop-up-bbdb-buffer)))) + + +;;;###autoload +(defun bbdb-insinuate-vm () + "Call this function to hook BBDB into VM." + (cond ((boundp 'vm-select-message-hook) ; VM 5.36+ + (add-hook 'vm-select-message-hook 'bbdb/vm-pop-up-bbdb-buffer)) + ((boundp 'vm-show-message-hook) ; VM 5.32.L+ + (add-hook 'vm-show-message-hook 'bbdb/vm-pop-up-bbdb-buffer)) + (t + (error "vm versions older than 5.36 no longer supported"))) + (define-key vm-mode-map ":" 'bbdb/vm-show-sender) + ;; (define-key vm-mode-map "'" 'bbdb/vm-show-all-recipients) ;; not yet + (define-key vm-mode-map ";" 'bbdb/vm-edit-notes) + (define-key vm-mode-map "/" 'bbdb) + ;; VM used to inherit from mail-mode-map, so bbdb-insinuate-sendmail + ;; did this. Kyle, you loser. + (if (boundp 'vm-mail-mode-map) + (define-key vm-mail-mode-map "\M-\t" 'bbdb-complete-name))) + +(provide 'bbdb-vm) diff --git a/xemacs-packages/lisp/bbdb/bbdb-vm.elc b/xemacs-packages/lisp/bbdb/bbdb-vm.elc new file mode 100644 index 0000000000000000000000000000000000000000..abf9d828786d62ebbe0e8f93ec3c50a7ed887e60 GIT binary patch literal 12205 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 B(cb_7 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-w3.el b/xemacs-packages/lisp/bbdb/bbdb-w3.el new file mode 100644 index 00000000..a0c2dac1 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-w3.el @@ -0,0 +1,63 @@ +;;; This file is part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1991, 1992, 1993 Jamie Zawinski . +;;; WWW-related functions for the BBDB. See bbdb.texinfo. + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;; +;; $Id: bbdb-w3.el,v 1.6 2005/07/24 15:22:58 waider Exp $ +;; + +(require 'bbdb-com) +(require 'browse-url) + +(defvar w3-mode-map) +(eval-when-compile + (condition-case() (require 'url) (error (fset 'url-view-url 'ignore)))) + +;;;###autoload +(defun bbdb-www (rec &optional which) + "Visit URLs stored in the `www' field of the current record. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-www] \ +means to try all records currently visible. +Non-interactively, do all records if arg is nonnil." + (interactive (list (bbdb-get-record "Visit (WWW): ") + (or current-prefix-arg 0))) + (browse-url (read-string "fetch: " (bbdb-get-field rec 'www which)))) + +;;;###autoload +(defun bbdb-www-grab-homepage (record) + "Grab the current URL and store it in the bbdb database" + (interactive (list (bbdb-completing-read-one-record + "Add WWW homepage for: "))) + ;; if there is no database record for this person, create one + (unless record + (setq record (bbdb-read-new-record)) + (bbdb-invoke-hook 'bbdb-create-hook record)) + (if (bbdb-record-getprop record 'www) + (bbdb-record-putprop + record 'www + (concat (bbdb-record-getprop record 'www) "," (url-view-url t))) + (bbdb-record-putprop record 'www (url-view-url t))) + (bbdb-change-record record t) + (bbdb-display-records (list record))) + +;;;###autoload +(defun bbdb-insinuate-w3 () + "Call this function to hook BBDB into W3." + (add-hook 'w3-mode-hook + (lambda () (define-key w3-mode-map ":" 'bbdb-www-grab-homepage)))) + +(provide 'bbdb-w3) diff --git a/xemacs-packages/lisp/bbdb/bbdb-w3.elc b/xemacs-packages/lisp/bbdb/bbdb-w3.elc new file mode 100644 index 0000000000000000000000000000000000000000..5dd973bb7b8df4828c9ad31b8ae218f180aab078 GIT binary patch literal 1708 zcmZux-Hzil7@f;*uejizZ&Ji0(mGAs`C;0d-5FL$XaoWTMVeMxCvjV=j-7R!X37iD zOP&LGh@H;P!oo}OIZkKjvc0M8d_F$kImaHoxVrrK;NYM=8jT=PS zm{QON~px1|9G>p!NCw=Hg(Mb(3(<*}*LO{1HbXTZ^3LG(Abmg*} zFXtpKxk$T)6{dT`GMW@5r^%AeS<#K-H0}ys+SK{Fx%N9LfAiR>PD7(M51%j>$_@|8=mo> zsj+AA0$X?ay(K{rQE_T+WGLMUlfEEO`CM3xc3s*DF#Z{`UbS7kDV{x1tj(5qPg} z4>zy3hrf7mt=X%RYX&tD^aNt9s)CVHiz)PjcIR2Y7r~Fb;0Av9?y7*oD2;(bNzH=6 z%c`o5&;%w@P_ufep#T~!)@bcpwR`*L@8Q-Y;NJB z?Oki)ZQiu*C*JSBzHQytqd)(8cld2*^VC zj;-2#%xDf6dyd4HYz^M9$tUW#@Awpsr&Aa-Iqe;v4{ReoioW9bel#~`5VZdVCYd~9 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-whois.el b/xemacs-packages/lisp/bbdb/bbdb-whois.el new file mode 100644 index 00000000..f0621270 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-whois.el @@ -0,0 +1,263 @@ +;;; bbdb-whois.el -- Big Brother gets a little help from Big Brother +;;; This file is part of the Insidious Big Brother Database (aka BBDB). +;;; +;;; Copyright (C) 1992, 1993 Roland McGrath +;;; +;;; This program 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 program 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. +;;; +;;; A copy of the GNU General Public License can be obtained from this +;;; program's author (send electronic mail to roland@gnu.ai.mit.edu) or +;;; from the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA +;;; 02139, USA. +;;; +;;; Send bug reports to bbdb@waider.ie + +(require 'bbdb-com) + +(defmacro bbdb-add-to-field (record field text) + (let ((get (intern (concat "bbdb-record-" (symbol-name field)))) + (set (intern (concat "bbdb-record-set-" (symbol-name field))))) + (` (let ((old ((, get) (, record))) + (text (, text))) + (or (member text old) + ((, set) (, record) (nconc old (list text)))))))) + +(defcustom bbdb-whois-server (or (and (boundp 'whois-server) whois-server) + "whois.geektools.com") + "*Server for \\[bbdb-whois] lookups." + :group 'bbdb-utilities + :type 'string) + +(defvar bbdb-whois-name nil + "Used to store the name during a whois call.") +(make-variable-buffer-local 'bbdb-whois-name) +(defvar bbdb-whois-record nil + "Used to store the record during a whois call.") +(make-variable-buffer-local 'bbdb-whois-record) + +;;; main entry point. it'd be nice if we could bbdb-whois an arbitrary +;;; name and make a record from that directly. + +;;;###autoload +(defun bbdb-whois (the-record &optional server) + (interactive (list (bbdb-get-record "BBDB Whois: ") + (and current-prefix-arg + (read-string "Query whois server: " + bbdb-whois-server)))) + (or server (setq server bbdb-whois-server)) + (if (or (bbdb-record-lastname the-record) (bbdb-record-firstname the-record)) + ;; XXX we seem to get called with a vector of nils. + (save-excursion + (set-buffer (generate-new-buffer " *bbdb-whois*")) + (set bbdb-whois-record the-record) + (set bbdb-whois-name + (if (bbdb-record-getprop the-record 'nic) + (concat "!" (bbdb-record-getprop the-record 'nic)) + (concat (bbdb-record-lastname the-record) ", " + (bbdb-record-firstname the-record)))) + (let ((proc (open-network-stream "whois" (current-buffer) server 43))) + (set-process-sentinel proc 'bbdb-whois-sentinel) + (process-send-string proc (concat bbdb-whois-name "\r\n")))))) + +;;; This function parses the results from the server. +(defun bbdb-whois-sentinel (proc status) + (save-excursion + (let (rec) + (set-buffer (process-buffer proc)) + (setq rec bbdb-whois-record) + (goto-char 1) + + ;; check for multiple replies + ;; should maybe present a menu/completion buffer of multiples and do a + ;; refetch. + (if (not (re-search-forward "Record last updated" (point-max) t)) + (if (re-search-forward "No match" (point-max) t) + (message "Can not find a whois record for `%s'" bbdb-whois-name) + (if (re-search-forward "Access Limit Exceeded" (point-max) t) + (message "Per-day access limit to %s exceeded." + bbdb-whois-server) ;; bah! + (message "%s is ambiguous to whois; try a different name" + bbdb-whois-name))) + + ;; clean up & parse buffer, otherwise. + (replace-string "\r\n" "\n") + (goto-char 1) + (if (re-search-forward + (concat (if (string-match "^!" bbdb-whois-name) + (concat "(\\(" + (regexp-quote (substring bbdb-whois-name 1)) + "\\))") + (concat (regexp-quote bbdb-whois-name) + ".*(\\([A-Z0-9]+\\))")) + "\\s *\\(\\S +@\\S +\\)?$") + nil t) + (let ((net (if (match-beginning 2) + (downcase (buffer-substring (match-beginning 2) + (match-end 2))))) + (nic (buffer-substring (match-beginning 1) (match-end 1))) + (lines nil)) + (if net + (bbdb-add-to-field rec net net)) + (bbdb-record-putprop rec 'nic nic) + + ;; Snarf company. + ;; not all nic records have companies, though. + (forward-line 1) + (back-to-indentation) + (let ((company (buffer-substring (point) (progn (end-of-line) + (point)))) + (old (bbdb-record-company rec))) + (cond ((not old) + (bbdb-record-set-company rec company)) + ((string= old company) + nil) + (t + (bbdb-record-putprop rec 'nic-organization company)))) + + ;; Read the address info into LINES. + (while (progn (forward-line 1) + (not (looking-at "^$"))) + (back-to-indentation) + (setq lines (cons (buffer-substring (point) + (progn (end-of-line) + (point))) + lines))) + + ;; Snarf phone number. + ;; phone, fax are presented, it seems, as + ;; +country area prefix number +country area prefix number + ;; we can look for the " +" and split there, I guess. + (if (car lines) + (let ((phones (car lines)) + (n 1) + phone-numbers) + (while (string-match "^\\(.+\\) \\+" phones) + (setq phone-numbers + (append phone-numbers + (list (substring phones 0 (match-end 1)))) + phones (substring phones (+ 1 (match-end 1))))) + (setq phone-numbers (append phone-numbers + (list phones))) + + ;; now add each member of the list to the bbdb record + ;; it'd be nice if we could be smarter about this. + (mapcar (function + (lambda(p) + (if (not (bbdb-find-phone + p (bbdb-record-phones rec))) + (let ((p-n + (vector (format "nic-phone-%d" n) p))) + (bbdb-add-to-field rec phones p-n) + (setq n (+ 1 n)))))) + phone-numbers) + + ;; throw away phones line from what we've snarfed + (setq lines (cdr lines)))) + + ;; Snarf address. + (if (car lines) + (let ((addr (make-vector bbdb-address-length nil)) + (city "") + (state "") + (zip "") + (country "")) + + ;; extract country + (if (string-match "^[A-Z][A-Z]$" (car lines)) + (setq country (car lines) ;; could convert from ISO... + lines (cdr lines))) + + ;; extract city, state, zip + ;; it would be nice if this could all use bbdb-snarf. + ;; or if NICs would hand out something machine + ;; readable, like XML. + ;; + ;; note the zipcode check at the end of the regexp + ;; isn't really a zipcode check, because we don't do + ;; zipcode checks any more. + (if (string-match + "\\([^,]+\\),\\s *\\(\\S +\\)\\s *\\(.+\\)" + (car lines)) + (setq city (substring (car lines) + (match-beginning 1) + (match-end 1)) + state (substring (car lines) + (match-beginning 2) + (match-end 2)) + zip (substring (car lines) + (match-beginning 3) + (match-end 3)) + lines (cdr lines)) + ;; otherwise we just stuff everything into the + ;; streets list and let the user clean it up. This + ;; would be nice to do heuristically, if I knew + ;; enough about variable address formats. + ;; (bbdb-snarf-grok-address (ADDR)) would be neat. + ) + + (bbdb-address-set-location addr "nic-address") + (bbdb-address-set-city addr (or city "")) + (bbdb-address-set-state addr (or state "")) + (bbdb-address-set-zip addr (or zip "")) + (bbdb-address-set-country addr (or country "")) + (setq lines (nreverse lines)) + (bbdb-address-set-streets addr lines) + + ;; should probably overwrite existing nic-address field. + (bbdb-add-to-field rec addresses addr))) + + ;; Snarf any random notes. + (setq lines nil) + (while (progn + (forward-line 1) + (back-to-indentation) + (not (looking-at + "$\\|Record last updated on"))) + (if (looking-at "Alternate mailbox: \\(\\S +\\)$") + (bbdb-add-to-field rec net + (buffer-substring (match-beginning 1) + (match-end 1))) + (setq lines (cons (buffer-substring (point) + (progn (end-of-line) + (point))) + lines)))) + (if lines + (bbdb-record-putprop rec 'nic-notes + (mapconcat 'identity + (nreverse lines) + "\n"))) + + ;; Snarf the last-update date. + (if (re-search-forward "Record last updated on \\(\\S *\\)\\." + nil t) + (bbdb-record-putprop rec 'nic-updated + (buffer-substring (match-beginning 1) + (match-end 1)))) + + (save-excursion + (set-buffer bbdb-buffer-name) + (bbdb-redisplay-one-record rec))) + (message "No whois information for %s" bbdb-whois-name))) + (delete-process proc) + (kill-buffer (current-buffer))))) + +(defun bbdb-find-phone (string record) + "Return the vector entry if STRING is a phone number listed in RECORD." + (let ((phone nil) + (done nil)) + (while (and record (not done)) + (setq phone (car record)) + (if (string= string (bbdb-phone-string phone)) + (setq done phone)) + (setq record (cdr record))) + done)) + +(provide 'bbdb-whois) diff --git a/xemacs-packages/lisp/bbdb/bbdb-whois.elc b/xemacs-packages/lisp/bbdb/bbdb-whois.elc new file mode 100644 index 0000000000000000000000000000000000000000..75ba7fb63ff4d686ba10d58757bfd2a6f4eaa16c GIT binary patch literal 3841 zcmb7HTW}Ov8D96rOfoZ7tB_Kn;hzr3OrR$hZjx}Bgk(3_qBh}TttB0bp6-)Lo1X5b zyN4u;RhDca9VmUUpyWljtg_0gWblzEAAFEu0%WhCtFkDfuDV{<`|ZW=oYO;+U93{7 z$aJ6cpa1;-_kaJT`-cx5T=&EiPc--U_mkn4JXrn|i9l3J`- zw%HZ3AnclDW!(r=PdBFZ5(~PDMYGstTY)E@)R`&Q3i8YriiIehh9V0#^!DU;P}b8! zV~Toq=SX?BQZBl5bjr8No z+Vw)KY`vg|{4Ohi*K$3a!i(?@E@9a-Tob=DQx@znU2@!z*sK+VWH}^l=-HERZq8bh zl+_)RvPHMzm>zABp2zOwniG_D{r8G^t})fu*N`E$_8n*VzibftmQzw~76cxxQAnu!AjI8AtB8cCt*0Zs$sKH@qOlms_p8giZF#a+|I&N z^u7&pEF1UYyw6TmET7R9aV;W{YtEW%QnxMKD;IUsR6|#tw3uzumMkLYyOgJn<2Y=% zz6rqjPRM3)p>n-;Bbgb`T(66twhc=+H77AN^xdYRpRD#egt0psS-Dm1)-M922l0+gPh^`_@5Nja7uUJEt)%!WH4QUZe z0}z=dCB~*h*R_K@FjlbKc~q+7A=R|wD^Z^y+jXZaUXWL)ujIQGuu<$*Ld&*73w-Vi z=RDXZnU!nqDD2otp9+xnp-b=s;S8r338c&lXCLX(Dnho~`HdpP@R3$-mAHZyl(eW6pf*fSG9Ltko;BF;yM!UTA7e-y7_Y zyahUHe90$xDRCXRBg2cxB&%l=>r%Cm>bca7k*n7()R!`+qNdcLNONwcZfVM5bX)w6 zFGP@9hS1?d(aW!R$yYbEz1H%&rbKVFXwIE+O%Xg_g>ii6s+E{it5!tRJl{29gLo(# z#`aJ*m6*ePJ!GoGX5x5|LY*rbIu#jKd6|mTf;JBsZ;+BvNZAH)*JBP8gfp%`t%62O zFULexXvcP*iYhk&B?~-uLd#+HYOXw5TP0+2J)CMvN^_J6+R1AS$z;n4>tIR45oK_2 zXpo-giPA^N29ZvUD&_fX(wbFuzeK1oC}j=BhbzpVi-|0O!{N1d@eD;po%k=oU-1Sk zkRXS8SP2mI3$>5kNFPL`(@(Ff7o(+{=BXE9oSxd~xC+xq0vEBt+a`PK9@ za$)(kc<1#u?qG$Vy!(ADEnfV=n@#oFSmuX^7tX!el=;#4kH>4bI$nJ0$$OWse(~O= zdza6AwSK97`AqHO?HlLYhZe6S-x^5|ZD`Y+mTT3E$+tkEgWnvDZnX|~-cSA{y|E*z z&qY6_=w$8l(aAH(2P19m`&+6}@sPO4C^weM{oY2SDE7wLVl^U5#Nd(->gu3sKIs41;@tY1D>8*AOSpocCDy~O6>A2Zdf5C4=|{2IU%=sp(Dg`*Ng4$4Ss@#6jD zpa1gL)Ju0dI-;e&AxMiC?kE2)j(0>C($AiX{*lZ?+ZN6(|C7i1Utme}Z!h!SwK`>u6CG&qSV^3WcOR=Teyu zQwo)llo-ZHIjB2go|&{Tw>0W|Tw!=qIk`F5f^;7+cpB3o%u68+&l-%GT&FUQI&SK7 zq|1FjoTK zRSZZ$ML=T`bC7U@loPxZWi>6!kCfP~r=F^~A>7imTn=0LPQH13K>bX&x@Tf*ysBvd zbz)u9j?&hG_=}wbn-uD$T_mbZT=u-mO4%!7e&rJkfP$fNXxz>VqU!o3-D%8`yzTNy zO$Xj5pi()3oAUf>H0Z4g=^m=4i4t7aJp;{?mk<<=S^^zFQx07HMt$jKQd1I|@)4{w zwQT@DuT`Ve4Wu+r<<8`>`E@xy`gp2Co)|{N5abA=2b+d^AyJG@|@a8O~6mBrbYeM|t_HzJFY!l#ZTZ0^2YP<{oAj_3=@`5X90jS=} zCQbX?W9W!k8{z{tAJITh*kIX3ceW20$*@2H-hA7J z#Ny?a>Q@ql4>euaoXnNQvzqha#K8Ph)#(;d4cDBB?>9M@`6wV9myk<2P&ghox9{ri R6+Ij1o(4-+kCwUS{{T?EL4*JR literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/bbdb/bbdb-xemacs.el b/xemacs-packages/lisp/bbdb/bbdb-xemacs.el new file mode 100644 index 00000000..456c0af3 --- /dev/null +++ b/xemacs-packages/lisp/bbdb/bbdb-xemacs.el @@ -0,0 +1,113 @@ +;;; -*- Mode:Emacs-Lisp -*- +;;; This file contains some XEmacs-specific stuff for BBDB. + +;;; This file is the part of the Insidious Big Brother Database (aka BBDB), +;;; copyright (c) 1992, 1993, 1994 Jamie Zawinski . + +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; This code is kind of kludgey, mostly because it needs to parse the contents +;;; of the *BBDB* buffer, since BBDB doesn't save the buffer-positions of the +;;; various fields when it fills in that buffer (doing that would be slow and +;;; cons a lot, so it doesn't seem to be worth it.) + +(or (string-match "XEmacs\\|Lucid" emacs-version) + (error "This file only works in XEmacs.")) + +;; this makes no sense, long-term, but. +(eval-when-compile + (or (featurep 'xemacs) + (fset 'load-sound-file 'ignore))) + +(require 'bbdb) +(require 'bbdb-com) +(require 'bbdb-gui) ;; load in the menu/font stuff + +;; Utility functions that mask others to provide XEmacs-specific functionality +;;;###autoload +(defun bbdb-xemacs-display-completion-list (list &optional callback data) + "Wrapper for `display-completion-list'. +Allows callbacks on XEmacs `display-completion-list' is called with +`:activate-callback CALLBACK' if CALLBACK is non-nil. +`:user-data DATA' is also used if DATA is non-nil. +Neither are used if CALLBACK is nil." + (cond ((and callback data) + (display-completion-list list + :activate-callback callback + :user-data data)) + (callback + (display-completion-list list + :activate-callback callback)) + (t + (display-completion-list list)))) + + +;; For native Xemacs sound support we can use these ... +;;;###autoload +(defcustom bbdb-sounds-directory (expand-file-name "~/.xemacs/etc/sounds") + "The directory to load the touchtone sound files from, or nil if none." + :group 'bbdb-phone-dialing + :type 'directory) + +;;;###autoload +(defcustom bbdb-sound-volume 50 + "Volume for playing sounds." + :group 'bbdb-phone-dialing + :type 'integer) + +;;;###autoload +(defun bbdb-load-touchtones () + "Load the touchtone sounds into `sound-alist'. +The directory specified in `bbdb-sounds-directory' is searched for the files +touchtone.*\\.\\(wav\\|au\\) as named in `bbdb-sound-files'. +They are stored in `sound-alist' as touchtone0 to touchtone11." + (interactive) + (let (files + (nr 0)) + (condition-case nil + (setq files + (directory-files bbdb-sounds-directory t + (if (and system-type + (string-match + "windows" + (format "%s" system-type))) + "touchtone.*\\.wav" + "touchtone.*\\.au"))) + (error + ;; It is not a fatal error if we can't find the touchtones; it + ;; just prevents a particular, possibly little-used feature + ;; from working. + (bbdb-warn "Cannot find any touchtone sounds") + (setq files nil))) + + (if (not files) + (progn + (message "No touchtone files found in `bbdb-sound-directory'!") + (sit-for 2)) + ;; otherwise, load 'em up. + (while files + (load-sound-file (car files) + (intern (concat "touchtone" (format "%d" nr))) + bbdb-sound-volume) + (setq files (cdr files) + nr (1+ nr)))))) + +(if (and bbdb-sounds-directory + (file-directory-p bbdb-sounds-directory) + (boundp 'xemacsp) + (featurep 'native-sound)) + (bbdb-load-touchtones)) + +(provide 'bbdb-xemacs) diff --git a/xemacs-packages/lisp/bbdb/bbdb-xemacs.elc b/xemacs-packages/lisp/bbdb/bbdb-xemacs.elc new file mode 100644 index 0000000000000000000000000000000000000000..b56c18bd2be8cc76b0c9d83e5744291f7ba4c984 GIT binary patch literal 2501 zcma)8TW=dh6z*fSeuR)_$Tek(;nd(6s zOF%W(Sv64+OYn+kx+)K=>0!rjcBTQs50#4k%$AE-WnQC?B*4M z#>O;mi}2U{+NNJ`6wxX*q9?v(hRzZiX&28;7jG;*lBvCg43uup68Wp9M3X5!Z{$7=h{|a!1TQDZ44=J+f+nOuuefod6sc${6w+X$3__s zkLTtNyz&J|k>J6YPr~~o6F5(vu7u9xA0|iT(eVj>p5fQ~xc|N>JKP5;Z`nSdz5Rv1E!nSn6f(m|6&M)Vm; zGOYtU+q=7;Z0~$t0W`_!4JArE8)XbIizdjAnPKqh_TDx|YG8?0fX`z}qo+$LH#r`M zoEQpl8njd!>%L!dW8P+oKm$}3T;ZRi0j%A2sp;?mjfavfnTY{}4W}@aqsi(~ zD34bzKfwDR?akVQ$*S$NC1I<~1UT=w*Jw2tVjr%7yLJfz*x0Cf`(DY7a&1)4k9m|J zYroGj!CJV83Tm3>P9wF9M@D5ssJQ%YiX-XMIQx?I(4gN{gJS7axrwSpii5QFx*X=2 zMga`~puk{M9(9e99Bj1R4Y(n23w{V_Cu|?J2Rq5pkrSJ1`I*Tprtm>f)13kGj=vXF*%cxGqf>Q&f1haim@@;|VZeZ;N} zj>fV+I^~gQ3v#A}V%-!#=IUDqYtFK$i(v$r#H3E>(oE9eN*ILhfc3+BEDt?En^K$3 zmbDGk1&X0HJo+G;hArZx0<+>Zyqw?F>#vyxyX9sH8tqT*bS6jdzBf5O`E?Y^#}A)9 zFOOclEI;}qlz;yIS17Ol{m;Mut%lB*<&`xI*nWF;@2y9jE41Tm*9$z;wn^MMMA_P; zhHG}dD(%pWe?C5W_B@oK6FTGjFCKmWa_!=TN)=i2f{VV^Lv47^w|<)0sn7@vEU(sq zkTLEwhdO}U7M#m??aU}+1Hu6Hf8`m=oqhNim%m#q<3;38o|Z?GhZoPl9I#A+v%@64 zA=`K?Fgcv-KXs}@O3-HZJm}&34F4+t=jKA6PUnk;`HZ_3%vE+k3*(cm8g^9uLUxjk z{L2Z;jO7CR7-?-x*GheT9T^fHoW+ICtc-tqvQi%Z@^n%jkB*MZ>Qn+!t`}oteO. +;;; See the file bbdb.texinfo for documentation. +;;; +;;; The Insidious Big Brother Database 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. +;;; +;;; BBDB 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;;; +;;; ------------------------------------------------------------------------ +;;; | There is a mailing list for discussion of BBDB: | +;;; | bbdb-info@lists.sourceforge.net | +;;; | To join, send mail to bbdb-info-request@lists.sourceforge.net | +;;; | (don't forget the "-request" part or you'll look silly in front of | +;;; | lots of people who have the ability to remember it indefinitely...) | +;;; | | +;;; | There is also a second mailing list, to which only bug fixes and | +;;; | new version announcements are sent; to be added to it, send mail to | +;;; | bbdb-announce-request@lists.sourceforge.net. This is a very low | +;;; | volume list, and if you're using BBDB, you really should be on it. | +;;; | | +;;; | When joining these lists or reporting bugs, please mention which | +;;; | version you have. The preferred method of reporting bugs is to use | +;;; | bbdb-submit-bug-report, which will include all useful version | +;;; | information plus state information about how you have BBDB set up. | +;;; ------------------------------------------------------------------------ +;;; +;;; $Id: bbdb.el,v 1.9 2005/07/24 15:22:58 waider Exp $ + +(require 'timezone) +(eval-when-compile (require 'cl)) + +(eval-when-compile ; pacify the compiler. + (autoload 'widget-group-match "wid-edit") + (autoload 'Electric-pop-up-window "electric") + (autoload 'Electric-command-loop "electric") + (autoload 'bbdb-migration-query "bbdb-migrate") + (autoload 'bbdb-migrate "bbdb-migrate") + (autoload 'bbdb-migrate-rewrite-all "bbdb-migrate") + (autoload 'bbdb-migrate-update-file-version "bbdb-migrate") + (autoload 'bbdb-unmigrate-record "bbdb-migrate") + (autoload 'bbdb-redisplay-records "bbdb-com") + (autoload 'bbdb-create-internal "bbdb-com") + (autoload 'bbdb-append-records-p "bbdb-com") + (autoload 'y-or-n-p-with-timeout "timer") + (autoload 'mail-position-on-field "sendmail") + (autoload 'bbdb-fontify-buffer "bbdb-gui") + ;; autoload doesn't work for these + (condition-case nil (require 'message) + (error (message "Warning: message not found. Ensure it is in your `load-path'"))); for message-mode-map + (require 'sendmail); for mail-mode-map + ) + +(defconst bbdb-version "2.35") +(defconst bbdb-version-date "$Date: 2005/07/24 15:22:58 $") + +(defcustom bbdb-gui (if (fboundp 'display-color-p) ; Emacs 21 + (display-color-p) + (not (null window-system))) ; wrong for XEmacs? + "*Non-nil means fontify the *BBDB* buffer." + :group 'bbdb + :type 'boolean) + +;; File format +(defconst bbdb-file-format 6) +(defvar bbdb-file-format-migration nil + "A cons of two elements: the version read, and the version to write. +nil if the database was read in and is to be written in the current +version.") + +(defvar bbdb-no-duplicates-p nil + "Should BBDB allow entries with duplicate names. +This may lead to confusion when doing completion. If non-nil, it will +prompt the users on how to merge records when duplicates are detected.") + +;; Definitions for things that aren't in all Emacsen and that I really +;; would prefer not to live without. +(eval-and-compile + (if (fboundp 'unless) nil + (defmacro unless (bool &rest forms) `(if ,bool nil ,@forms)) + (defmacro when (bool &rest forms) `(if ,bool (progn ,@forms)))) + (unless (fboundp 'save-current-buffer) + (defalias 'save-current-buffer 'save-excursion)) + (if (fboundp 'mapc) + (defalias 'bbdb-mapc 'mapc) + (defalias 'bbdb-mapc 'mapcar)) + ) + +(unless (fboundp 'with-current-buffer) + (defmacro with-current-buffer (buf &rest body) + `(save-current-buffer (set-buffer ,buf) ,@body))) + +(unless (fboundp 'defvaralias) + (defun defvaralias (&rest args))) + +(defmacro string> (a b) (list 'not (list 'or (list 'string= a b) + (list 'string< a b)))) + +(eval-and-compile + (or (fboundp 'set-keymap-prompt) + (fset 'set-keymap-prompt 'ignore))) + +;; this should really be in bbdb-com +;;;###autoload +(defun bbdb-submit-bug-report () + "Submit a bug report, with pertinent information to the BBDB info list." + (interactive) + (require 'reporter) + (delete-other-windows) + (reporter-submit-bug-report + "bbdb-info@lists.sourceforge.net" + (concat "BBDB " bbdb-version) + (append + ;; non user variables + '(emacs-version + bbdb-version-date + bbdb-file-format + bbdb-no-duplicates-p) + ;; user variables + (sort (apropos-internal "^bbdb" + 'user-variable-p) + (lambda (v1 v2) (string-lessp (format "%s" v1) (format "%s" v2)))) + ;; see what the user had loaded + (list 'features) + ) + nil + nil + "Please change the Subject header to a concise bug description.\nIn this report, remember to cover the basics, that is, what you expected to\nhappen and what in fact did happen. Please remove these\ninstructions from your message.") + + ;; insert the backtrace buffer content if present + (let ((backtrace (get-buffer-create "*Backtrace*"))) + (when backtrace + (goto-char (point-max)) + (insert "\n\n") + (insert-buffer-substring backtrace))) + + (goto-char (point-min)) + (mail-position-on-field "Subject")) + +;; Make custom stuff work even without customize +;; Courtesy of Hrvoje Niksic +(eval-and-compile + (condition-case () + (require 'custom) + (error nil)) + (unless (and (featurep 'custom) (fboundp 'custom-declare-variable)) + ;; We have the old custom-library, hack around it! + (defmacro defgroup (&rest args) + nil) + (defmacro defcustom (var value doc &rest args) + `(defvar ,var ,value ,doc)) + (defmacro defface (var value doc &rest args) + `(make-face ,var)) + (defmacro define-widget (&rest args) + nil))) + +(defconst bbdb-have-re-char-classes (string-match "[[:alpha:]]" "x") + "Non-nil if this Emacs supports regexp character classes. +E.g. `[[:alnum:]]'.") + +;; Custom groups + +(defgroup bbdb nil + "The Insidious Big Brother Database." + :group 'news + :group 'mail) + +(put 'bbdb 'custom-loads '("bbdb-hooks" "bbdb-com")) + +(defgroup bbdb-hooks nil + "Hooks run at various times by the BBDB" + :group 'bbdb) + +(defgroup bbdb-record-display nil + "Variables that affect the display of BBDB records" + :group 'bbdb) + +(defgroup bbdb-record-creation nil + "Variables that affect the creation of BBDB records" + :group 'bbdb) + +(defgroup bbdb-noticing-records nil + "Variables that affect the noticing of new authors" + :group 'bbdb-record-creation) +(put 'bbdb-noticing-records 'custom-loads '("bbdb-hooks")) + +(defgroup bbdb-record-use nil + "Variables that affect the use of BBDB records" + :group 'bbdb) + +(defgroup bbdb-database nil + "Variables that affect the database as a whole" + :group 'bbdb) + +(defgroup bbdb-saving nil + "Variables that affect saving of the BBDB" + :group 'bbdb-database) + +(defgroup bbdb-mua-specific nil + "MUA-specific customizations" + :group 'bbdb) + +(defgroup bbdb-mua-specific-gnus nil + "Gnus-specific BBDB customizations" + :group 'bbdb-mua-specific) + +(put 'bbdb-mua-specific-gnus 'custom-loads '("bbdb-gnus")) + +(defgroup bbdb-mua-specific-gnus-scoring nil + "Gnus-specific scoring BBDB customizations" + :group 'bbdb-mua-specific-gnus) + +(put 'bbdb-mua-specific-gnus-scoring 'custom-loads '("bbdb-gnus")) + +(defgroup bbdb-mua-specific-gnus-splitting nil + "Gnus-specific splitting BBDB customizations" + :group 'bbdb-mua-specific-gnus) + +(put 'bbdb-mua-specific-gnus-splitting 'custom-loads '("bbdb-gnus")) + +(defgroup bbdb-mua-specific-vm nil + "VM-specific BBDB customizations" + :group 'bbdb-mua-specific) + +(put 'bbdb-mua-specific-vm 'custom-loads '("bbdb-vm")) + +(defgroup bbdb-phone-dialing nil + "Customizations for phone number dialing" + :group 'bbdb) +(put 'bbdb-phone-dialing 'custom-loads '("bbdb-com")) + +(defgroup bbdb-utilities nil + "Customize BBDB Utilities" + :group 'bbdb) + +(defgroup bbdb-utilities-finger nil + "Customizations for fingering from within the BBDB" + :group 'bbdb-utilities + :prefix "bbdb-finger") +(put 'bbdb-utilities-finger 'custom-loads '("bbdb-com")) + +(defgroup bbdb-utilities-ftp nil + "Customizations for using FTP sites stored in BBDB records." + :group 'bbdb-utilities) +(put 'bbdb-utilities-ftp 'custom-loads '("bbdb-ftp")) + +(defgroup bbdb-utilities-print nil + "Customizations for printing the BBDB." + :group 'bbdb-utilities + :prefix "bbdb-print") +(put 'bbdb-utilities-print 'custom-loads '("bbdb-print")) + +(defgroup bbdb-utilities-supercite nil + "Customizations for using Supercite with the BBDB." + :group 'bbdb-utilities + :prefix "bbdb/sc") +(if (or (featurep 'supercite) + (locate-library "supercite")) + (put 'bbdb-utilities-supercite 'custom-loads '("bbdb-sc"))) + +(defgroup bbdb-utilities-server nil + "Customizations for interfacing with the BBDB from external programs." + :group 'bbdb-utilities + :prefix "bbdb/srv") +(if (and (or (featurep 'gnuserv) (locate-library "gnuserv")) + (or (featurep 'itimer) (locate-library "itimer"))) + (put 'bbdb-utilities-server 'custom-loads '("bbdb-srv"))) + +;; BBDB custom widgets + +(define-widget 'bbdb-alist-with-header 'group + "My group" + :match 'bbdb-alist-with-header-match + :value-to-internal (lambda (widget value) + (if value (list (car value) (cdr value)))) + :value-to-external (lambda (widget value) + (if value (append (list (car value)) (cadr value))))) + +(defun bbdb-alist-with-header-match (widget value) + (widget-group-match widget + (widget-apply widget :value-to-internal value))) + +;; Customizable variables + +(defcustom bbdb-file "~/.bbdb" + "*The name of the Insidious Big Brother Database file." + :group 'bbdb-database + :type 'file) + +;; this should be removed, and the following put in place: +;; a hierarchical structure of bbdb files, some perhaps read-only, +;; perhaps caching in the local bbdb. This way you could have, e.g. a +;; company address book, with each person having access to it, and +;; then a local address book with personal stuff in it. +(defcustom bbdb-file-remote nil + "*The remote file to save the database to. +When this is non-nil, it should be a file name. +When BBDB reads `bbdb-file', it checks this file, + and if it is newer, downloads it. +When BBDB writes `bbdb-file', it also writes this file. + +This feature allows one to keep the database in one place while using +different computers, thus reducing the need for merging different files." + :group 'bbdb-database + :type '(choice (const :tag "none" nil) + (file :tag "remote file name"))) + +(defcustom bbdb-file-remote-save-always t + "*Should the `bbdb-file-remote' file be saved whenever the database is saved? +When nil, you will be asked." + :group 'bbdb-database + :type 'boolean) + +(unless (fboundp 'primep) + (defun primep (num) + (let ((lim (sqrt num)) (nu 2) (prime t)) + (while (and prime (< nu lim)) + (setq prime (/= 0 (mod num nu)) + nu (1+ nu))) + prime))) + +(defcustom bbdb-hashtable-size 1021 + "*The size of the bbdb hashtable. +BBDB hashtable is an obarray, so this must be a prime integer. +Set this to a prime number (much) larger than the size of your database +before loading it. +If you change this variable outside `customize', +you should reload `bbdb-file'." + :group 'bbdb-database + :type 'integer + :set (lambda (symb val) + (unless (primep val) + (error "`%s' must be prime, not %s" symb val)) + (set symb val) + (when (fboundp 'bbdb-records) + (bbdb-records)) + val)) + +(defcustom bbdb-default-area-code nil + "*The default area code to use when prompting for a new phone number. +This variable also affects dialing." + :group 'bbdb-record-creation + :type '(choice (const :tag "none" nil) + (integer :tag "Default Area Code")) + :set (lambda( symb val ) + (if (or (and (stringp val) + (string-match "^[0-9]+$" val)) + (integerp val) + (null val)) + (set symb val) + (error "%s must contain digits only." symb)))) + +(defcustom bbdb-lastname-prefixes + '("von" "Von" "de" "De") + "*List of lastname prefixes recognized in name fields. Used to +enhance dividing name strings into firstname and lastname parts." + :group 'bbdb-record-creation + :type '(repeat string)) + +(defcustom bbdb-default-domain nil + "*The default domain to append when prompting for a new net address. +If the address entered does not contain `[@%!]', `@bbdb-default-domain' +will be appended to it. + +The address will not be altered if bbdb-default-domain remains at its +default value of nil, or if one provides a prefix argument to the +bbdb-insert-new-field command." + :group 'bbdb-record-creation + :type '(choice (const :tag "none" nil) + (string :tag "Domain" :value nil))) + +(defcustom bbdb-north-american-phone-numbers-p t + "*Set this to nil if you want to enter phone numbers that aren't the same +syntax as those in North America (that is, [[1] nnn] nnn nnnn ['x' n*]). +If this is true, then some error checking is done so that you can't enter +incorrect phone numbers, and all phone numbers are pretty-printed the same +way. European phone numbers don't have as strict a syntax, however, so +this is a harder problem for them (on which I am punting). + +You can have both styles of phone number in your database by providing a +prefix argument to the bbdb-insert-new-field command." + :group 'bbdb-record-creation + :type 'boolean) + +(defcustom bbdb-electric-p nil + "*Whether bbdb mode should be `electric' like `electric-buffer-list'." + :group 'bbdb-record-display + :type 'boolean) + +(defcustom bbdb-case-fold-search (default-value 'case-fold-search) + "*This is the value of `case-fold-search' used by `bbdb' and friends. +This variable lets the case-sensitivity of ^S and of the bbdb +commands be different." + :group 'bbdb + :type 'boolean) + +;; these variables both need to be enabled for gnus mailreading to +;; work right. that's probably a bug, or something. +(defcustom bbdb/mail-auto-create-p t + "*If this is t, then VM, MH, and RMAIL will automatically create new bbdb +records for people you receive mail from. If this is a function name +or lambda, then it is called with no arguments to decide whether an +entry should be automatically created. You can use this to, for example, +not create records for messages which have reached you through a +particular mailing list, or to only create records automatically if +the mail has a particular subject." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Automatically create" t) + (const :tag "Prompt before creating" prompt) + (const :tag "Do not automatically create" nil) + (function :tag "Create with function" bbdb-))) + +(defcustom bbdb/news-auto-create-p nil + "*If this is t, then GNUS will automatically create new bbdb +records for people you receive mail from. If this is a function name +or lambda, then it is called with no arguments to decide whether an +entry should be automatically created. You can use this to, for +example, create or not create messages which have a particular +subject. If you want to autocreate messages based on the current +newsgroup, it's probably a better idea to set this variable to t or +nil from your `gnus-select-group-hook' instead." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Automatically create" t) + (const :tag "Prompt before creating" prompt) + (const :tag "Do not automatically create" nil) + (function :tag "Create with function" bbdb-))) + +(defcustom bbdb-quiet-about-name-mismatches nil + "*If this is true, then BBDB will not prompt you when it notices a +name change, that is, when the \"real name\" in a message doesn't correspond +to a record already in the database with the same network address. As in, +\"John Smith \" versus \"John Q. Smith \". +Normally you will be asked if you want to change it. +If set to a number it is the number of seconds to sit for while +displaying the mismatch message." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Prompt for name changes" nil) + (const :tag "Do not prompt for name changes" t) + (integer :tag + "Instead of prompting, warn for this many seconds"))) + +(defcustom bbdb-use-alternate-names t + "*If this is true, then when bbdb notices a name change, it will ask you +if you want both names to map to the same record." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Ask to use alternate names field" t) + (const :tag "Use alternate names field without asking" nil))) + +(defcustom bbdb-readonly-p nil + "*If this is true, then nothing will attempt to change the bbdb database +implicitly, and you will be prevented from doing it explicitly. If you have +more than one emacs running at the same time, you might want to arrange for +this to be set to t in all but one of them." + :group 'bbdb-database + :type '(choice (const :tag "Database is read-only" t) + (const :tag "Database is writable" nil))) + +(defcustom bbdb-continental-zip-regexp "^\\s *[A-Z][A-Z]?\\s *-\\s *[0-9][0-9][0-9]" + "Regexp matching continental zip codes. +Addresses with zip codes matching the regexp will be formated using +`bbdb-format-address-continental'. The regexp should match zip codes +of the form CH-8052, NL-2300RA, and SE-132 54." + :group 'bbdb-record-display + :type 'regexp) + +(defcustom bbdb-auto-revert-p nil + "*If this variable is true and the BBDB file is noticed to have changed on +disk, it will be automatically reverted without prompting you first. Otherwise +you will be asked. (But if the file has changed and you hae made changes in +memory as well, you will always be asked.)" + :group 'bbdb-saving + :type '(choice (const :tag "Revert unchanged database without prompting" t) + (const :tag "Ask before reverting database"))) + +(defcustom bbdb-notice-auto-save-file nil + "*If this is true, then the BBDB will notice when its auto-save file is +newer than the file is was read from, and will offer to revert." + :group 'bbdb-saving + :type '(choice (const :tag "Check auto-save file" t) + (const :tag "Do not check auto-save file" nil))) + +(defcustom bbdb-use-pop-up t + "If true, display a continuously-updating bbdb window while in VM, MH, +RMAIL, or GNUS. If 'horiz, stack the window horizontally if there is room." + :group 'bbdb-record-display + :type '(choice (const :tag "Automatic BBDB window, stacked vertically" t) + (const :tag "Automatic BBDB window, stacked horizontally" 'horiz) + (const :tag "No Automatic BBDB window" nil))) + +(defcustom bbdb-pop-up-target-lines 5 + "*Desired number of lines in a VM/MH/RMAIL/GNUS pop-up bbdb window." + :group 'bbdb-record-display + :type 'integer) + +(defcustom bbdb-completion-type nil + "*Controls the behaviour of `bbdb-complete-name'. If nil, completion is +done across the set of all full-names and user-ids in the bbdb-database; +if the symbol 'name, completion is done on names only; if the symbol 'net, +completion is done on network addresses only; if it is 'primary, then +completion is done only across the set of primary network addresses (the +first address in the list of addresses for a given user). If it is +'primary-or-name, completion is done across primaries and real names." + :group 'bbdb-record-use + :type '(choice (const :tag "Complete across names and net addresses" nil) + (const :tag "Complete across names" name) + (const :tag "Complete across net addresses" net) + (const :tag "Complete across primary net addresses" primary) + (const :tag "Complete across names and primary net addresses" + primary-or-name))) + +(defcustom bbdb-completion-display-record t + "*Whether `bbdb-complete-name' (\\\\[bbdb-complete-name] +in mail-mode) will update the *BBDB* buffer +to display the record whose email address has just been inserted." + :group 'bbdb-record-use + :type '(choice (const :tag "Update the BBDB buffer" t) + (const :tag "Don't update the BBDB buffer" nil))) + +(defcustom bbdb-user-mail-names nil + "*A regular expression identifying the addresses that belong to you. +If a message from an address matching this is seen, the BBDB record for +the To: line will be shown instead of the one for the From: line. If +this is nil, it will default to the value of (user-login-name)." + :group 'bbdb-noticing-records + :type (list 'choice '(const :tag "Use value of (user-login-name)" nil) + (list 'regexp :tag "Pattern matching your addresses" + (or (user-login-name) "address")))) + +(defcustom bbdb-always-add-addresses 'ask + "*If this is true, then when the Insidious Big Brother Database notices +a new email address for a person, it will automatically add it to the list of +addresses. If it is 'ask, you will be asked whether to add it. If it is nil +then new network addresses will never be automatically added nor the user will +be asked. + +When set to a function name the function should return one of these values. + +See also the variable `bbdb-new-nets-always-primary' for control of whether +the addresses go at the front of the list or the back." + :group 'bbdb-noticing-records + :type '(choice (const :tag "Automatically add new addresses" t) + (const :tag "Ask before adding new addresses" ask) + (const :tag "Never add new addresses" nil) + (const bbdb-ignore-some-messages-hook) + (const bbdb-ignore-most-messages-hook))) + +(defcustom bbdb-new-nets-always-primary nil + "*If this is true, then when the Insidious Big Brother Database adds a new +address to a record, it will always add it to the front of the list of +addresses, making it the primary address. If this is nil, you will be asked. +If it is the symbol 'never (really, if it is any non-t, non-nil value) then +new network addresses will always be added at the end of the list." + :group 'bbdb-noticing-records + :type '(choice (const :tag "New address automatically made primary" t) + (const :tag "Ask before making new address primary" nil) + (const :tag "Never make new address primary" never))) + +(defcustom bbdb-send-mail-style nil + "*Specifies which package should be used to send mail. +Should be 'vm, 'mh, 'mail, 'message, or 'gnus (or nil, meaning guess.)" + :group 'bbdb-record-use + :type '(choice (const :tag "Use VM to send mail" vm) + (const :tag "Use MH-E to send mail" mh) + (const :tag "Use send-mail mode to send mail" mail) + (const :tag "Use Message to send mail" message) + (const :tag "Use Mew to send mail" mew) + (const :tag "Use compose-mail to send mail" compose-mail) + (const :tag "Use gnus to send mail" gnus) + (const :tag "Guess which package to use" nil))) + +(defcustom bbdb-offer-save t + "*If t, then certain actions will cause the BBDB to ask you whether +you wish to save the database. If nil, then the offer to save will never +be made. If not t and not nil, then any time it would ask you, it will +just save it without asking." + :group 'bbdb-saving + :type '(choice (const :tag "Offer to save the database" t) + (const :tag "Never offer to save the database" nil) + (const :tag "Save database without asking" savenoprompt))) + +(defcustom bbdb-message-caching-enabled t + "*Whether caching of the message->bbdb-record association should be used +for the interfaces which support it (VM, MH, and RMAIL). This can speed +things up a lot. One implication of this variable being true is that the +`bbdb-notice-hook' will not be called each time a message is selected, but +only the first time. Likewise, if selecting a message would generate a +question (whether to add an address, change the name, etc) you will only +be asked that question the very first time the message is selected." + :group 'bbdb + :type '(choice (const :tag "Enable caching" t) + (const :tag "Disable caching" nil))) + +(defcustom bbdb-silent-running nil + "*If this is true, bbdb will suppress all its informational messages and +queries. Be very very certain you want to set this, because it will suppress +prompting to alter record names, assign names to addresses, etc." + :group 'bbdb + :type '(choice (const :tag "Run silently" t) + (const :tag "Disable silent running" nil))) + +(defcustom bbdb-mode-hook nil + "*Hook or hooks invoked when the *BBDB* buffer is created." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-list-hook nil + "*Hook or hooks invoked after the `bbdb-list-buffer' is filled in. +Invoked with no arguments." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-create-hook 'bbdb-creation-date-hook + "*Hook or hooks invoked each time a new BBDB record is created. Invoked +with one argument, the new record. This is called *before* the record is +added to the database. Note that `bbdb-change-hook' will be called as well. + +Hook functions can use the variable `bbdb-update-address-class' to determine +the class of an email address according to `bbdb-get-addresses-headers' and +the variable `bbdb-update-address-header' is set to the header the email +address was extracted from." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-change-hook 'bbdb-timestamp-hook + "*Hook or hooks invoked each time a BBDB record is altered. Invoked with +one argument, the record. This is called *before* the bbdb-database buffer +is modified. Note that if a new bbdb record is created, both this hook and +`bbdb-create-hook' will be called." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-after-change-hook nil + "*Hook or hooks invoked each time a BBDB record is altered. Invoked with +one argument, the record. This is called *after* the bbdb-database buffer +is modified, so if you want to modify the record each time it is changed, +you should use the `bbdb-change-hook' instead. Note that if a new bbdb +record is created, both this hook and `bbdb-create-hook' will be called." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-canonicalize-net-hook nil + "*If this is non-nil, it should be a function of one arg: a network address +string. Whenever the Insidious Big Brother Database \"notices\" a message, +the corresponding network address will be passed to this function first, as +a kind of \"filter\" to do whatever transformations upon it you like before +it is compared against or added to the database. For example: it is the case +that CS.CMU.EDU is a valid return address for all mail originating at a +machine in the .CS.CMU.EDU domain. So, if you wanted all such addresses to +be canonically hashed as user@CS.CMU.EDU, instead of as user@host.CS.CMU.EDU, +you might set this variable to a function like this: + + (setq bbdb-canonicalize-net-hook + '(lambda (addr) + (cond ((string-match \"\\\\`\\\\([^@]+@\\\\).*\\\\.\\\\(CS\\\\.CMU\\\\.EDU\\\\)\\\\'\" + addr) + (concat (substring addr (match-beginning 1) (match-end 1)) + (substring addr (match-beginning 2) (match-end 2)))) + (t addr)))) + +You could also use this function to rewrite UUCP-style addresses into domain- +style addresses, or any number of things. + +This function will be called repeatedly until it returns a value EQ to the +value passed in. So multiple rewrite rules might apply to a single address." + :group 'bbdb-hooks + :type 'function) + +(defcustom bbdb-canonicalize-redundant-nets-p t + "*If this is non-nil, redundant network addresses will be ignored. +If a record has an address of the form foo@baz.com, setting this to t +will cause subsequently-noticed addresses like foo@bar.baz.com to be +ignored (since we already have a more general form of that address.) +This is similar in function to one of the possible uses of the variable +`bbdb-canonicalize-net-hook' but is somewhat more automatic. (This +can't quite be implemented in terms of the canonicalize-net-hook because +it needs access to the database to determine whether an address is +redundant, and the canonicalize-net-hook is purely a textual manipulation +which is performed before any database access.)" + :group 'bbdb-noticing-records + :type '(choice (const :tag "Ignore redundant addresses" t) + (const :tag "Don't ignore redundant addresses" nil))) + +(defcustom bbdb-notice-hook nil + "*Hook or hooks invoked each time a BBDB record is \"noticed\", that is, +each time it is displayed by the news or mail interfaces. Invoked with +one argument, the new record. The record need not have been modified for +this to be called - use `bbdb-change-hook' for that. You can use this to, +for example, add something to the notes field based on the subject of the +current message. It is up to your hook to determine whether it is running +in GNUS, VM, MH, or RMAIL, and to act appropriately. + +Also note that `bbdb-change-hook' will NOT be called as a result of any +modifications you may make to the record inside this hook. + +Hook functions can use the variable `bbdb-update-address-class' to determine +the class of an email address according to `bbdb-get-addresses-headers' and +the variable `bbdb-update-address-header' is set to the header the email +address was extracted from. + +Beware that if the variable `bbdb-message-caching-enabled' is true (a good +idea) then when you are using VM, MH, or RMAIL, this hook will be called only +the first time that message is selected. (The GNUS interface does not use +caching.) When debugging the value of this hook, it is a good idea to set +caching-enabled to nil." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-after-read-db-hook nil + "*Hook or hooks invoked (with no arguments) just after the Insidious Big +Brother Database is read in. Note that this can be called more than once if +the BBDB is reverted." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-load-hook nil + "*Hook or hooks invoked when the BBDB code is first loaded. + +WARNING: This hook will be run the first time you traverse the Custom menus + for the BBDB. As a result, nothing slow should be added to + this hook." + :group 'bbdb-hooks + :type 'hook) + +(defcustom bbdb-initialize-hook nil + "*Hook or hooks invoked (with no arguments) when the Insidious Big Brother +Database initialization function `bbdb-initialize' is run." + :group 'bbdb-hooks + :type 'hook) + +(defvar bbdb-mode-map nil + "Keymap for Insidious Big Brother Database listings.") +(defvar bbdb-mode-search-map nil + "Keymap for Insidious Big Brother Database searching") + +;; iso-2022-7bit should be OK (but not optimal for Emacs, at least -- +;; emacs-mule would be better) with both Emacs 21 and XEmacs. Emacs +;; 22 will really need utf-8-emacs. +(defconst bbdb-file-coding-system (if (fboundp 'coding-system-p) + (cond ((coding-system-p 'utf-8-emacs) + 'utf-8-emacs) + ((coding-system-p 'mule-utf-8) + 'mule-utf-8) + (t 'iso-2022-7bit))) + "Coding system used for reading and writing `bbdb-file'. +This should not be changed by users.") + +(defvar bbdb-suppress-changed-records-recording nil + "Whether to record changed records in variable `bbdb-changed-records'. + +If this is false, the BBDB will cease to remember which records are changed +as the change happens. It will still remember that records have been changed, +so the file will still be saved, but the changed records list, and the `!!' +in the *BBDB* buffer modeline that it depends on, will no longer be updated. + +You should bind this variable, not set it; the `!!' is a useful user- +interface feature, and should only be suppressed when changes need to be +automatically made to BBDB records which the user will not care directly +about.") + + +;;; These are the buffer-local variables we use. +;;; They are mentioned here so that the compiler doesn't warn about them +;;; when byte-compile-warn-about-free-variables is on. + +(defvar bbdb-records nil) +(defvar bbdb-changed-records nil) +(defvar bbdb-end-marker nil) +(defvar bbdb-hashtable nil) +(defvar bbdb-propnames nil) +(defvar bbdb-message-cache nil) +(defvar bbdb-showing-changed-ones nil) +(defvar bbdb-modified-p nil) +(defvar bbdb-address-print-formatting-alist) ; "bbdb-print" + +(defvar bbdb-debug t) +(defmacro bbdb-debug (&rest body) + ;; ## comment out the next line to turn off debugging. + ;; ## You really shouldn't do this! But it will speed things up. + (list 'and 'bbdb-debug (list 'let '((debug-on-error t)) (cons 'progn body))) + ) + + +;;; internal kludge to force queries to always happen with the mouse rather +;;; than basing the decision on the last-input-event; bind this, don't set it. +(defvar bbdb-force-dialog-boxes nil) + +(defun bbdb-y-or-n-p (prompt) + (prog1 + (funcall + (cond ((and bbdb-force-dialog-boxes + (fboundp 'yes-or-no-p-dialog-box)) + (when (and (fboundp 'raise-frame) + (not (frame-visible-p (selected-frame)))) + (raise-frame (selected-frame))) + 'yes-or-no-p-dialog-box) + (t 'y-or-n-p)) + prompt) + (message " "))) + +(defun bbdb-yes-or-no-p (prompt) + (prog1 + (funcall (if (and bbdb-force-dialog-boxes + (fboundp 'yes-or-no-p-dialog-box)) + 'yes-or-no-p-dialog-box + 'yes-or-no-p) + prompt) + (message " "))) + +(defun bbdb-invoke-hook (hook arg) + "Like `invoke-hooks', but invokes the given hook with one argument." + (if (and (boundp hook) (setq hook (symbol-value hook))) + (if (and (consp hook) (not (eq (car hook) 'lambda))) + (while hook + (funcall (car hook) arg) + (setq hook (cdr hook))) + (funcall hook arg)))) + +(defun bbdb-invoke-hook-for-value (hook &rest args) + "If HOOK is nil, return nil. If it is t, return t. Otherwise, +return the value of funcalling it with the rest of the arguments." + (cond ((eq hook nil) nil) + ((eq hook t) t) + ((functionp hook) (apply hook args)) + (t hook))) + +(defmacro bbdb-defstruct (conc-name &rest slots) + "Make two functions, one for each slot. The functions are: + CONC-NAME + SLOT and CONC-NAME + `set-' + SLOT +The first one is to be used to read the element named in SLOT, and the +second is used to set it. Also make a constant + CONC-NAME + `length' +that holds the number of slots." + (setq conc-name (symbol-name conc-name)) + (let ((body '()) + (i 0) + (L (length slots))) + (while slots + (setq body + (nconc body + (let ((readname (intern (concat conc-name (symbol-name (car slots))))) + (setname (intern (concat conc-name "set-" (symbol-name (car slots)))))) + (list + (list 'defmacro readname '(vector) + (list 'list ''aref 'vector i)) + (list 'defmacro setname '(vector value) + (list 'list ''aset 'vector i 'value)) + ;(list 'put (list 'quote readname) ''edebug-form-hook ''(form)) + ;(list 'put (list 'quote setname) ''edebug-form-hook ''(form form)) + )))) + (setq slots (cdr slots) i (1+ i))) + (setq body (nconc body (list (list 'defconst + (intern (concat conc-name "length")) + L)))) + (cons 'progn body))) + +;;; When reading this code, beware that "cache" refers to two things. +;;; It refers to the cache slot of bbdb-record structures, which is +;;; used for computed properties of the records; and it also refers +;;; to a message-id --> bbdb-record association list which speeds up +;;; the RMAIL, VM, and MH interfaces. + +;; Build reading and setting functions for firstname, lastname, aka, +;; company, phones, addresses, net, raw-notes, and cache. These are +;; for accessing the high-level forms for the record. +(bbdb-defstruct bbdb-record- + firstname lastname aka company + phones addresses net raw-notes + cache + ) + +;; HACKHACK +(defmacro bbdb-record-set-net (vector value) + "We redefine the set-binding for 'net to detect changes" + (list 'progn + (list 'aset vector 6 value) + (list 'setq 'bbdb-define-all-aliases-needs-rebuilt t))) + +(put 'company 'field-separator "; ") +(put 'notes 'field-separator "\n") + +;; Build reading and setting functions for location, area, exchange, +;; suffix, and extension. These are for accessing the elements of the +;; individual phone number forms. +(bbdb-defstruct bbdb-phone- + location area exchange suffix extension + ) + +;; Build reading and setting functions for location, street, city, +;; state, zip and country. These are for accessing the elements of +;; the individual address forms. +(bbdb-defstruct bbdb-address- + location streets city state zip country + ) + +;; Build reading and setting functions for namecache (the full name of +;; the person referred to by the record), sortkey (the concatenation +;; of the elements used for sorting the record), marker, and +;; deleted-p. These are for accessing the elements of the cache form, +;; and are generally concatenations of data existing in separate parts +;; of the record, stored here prebuilt for speed. +(bbdb-defstruct bbdb-cache- + namecache sortkey marker deleted-p + ) + +;; Build the namecache for a record +(defsubst bbdb-record-name-1 (record) + (bbdb-cache-set-namecache (bbdb-record-cache record) + (let ((fname (bbdb-record-firstname record)) + (lname (bbdb-record-lastname record))) + (if (> (length fname) 0) + (if (> (length lname) 0) + (concat fname " " lname) + fname) + lname)))) + +;; Return the full name from a record. If the name is not available +;; in the namecache, the namecache value is generated (and stored). +(defun bbdb-record-name (record) + (or (bbdb-cache-namecache (bbdb-record-cache record)) + (bbdb-record-name-1 record))) + +;; Return the sortkey for a record, building (and storing) it if +;; necessary. +(defun bbdb-record-sortkey (record) + (or (bbdb-cache-sortkey (bbdb-record-cache record)) + (bbdb-cache-set-sortkey (bbdb-record-cache record) + (downcase + (concat (bbdb-record-lastname record) + (bbdb-record-firstname record) + (bbdb-record-company record)))))) + +(defmacro bbdb-record-marker (record) + (list 'bbdb-cache-marker (list 'bbdb-record-cache record))) + +(defmacro bbdb-record-deleted-p (record) + (list 'bbdb-cache-deleted-p (list 'bbdb-record-cache record))) + +(defmacro bbdb-record-set-deleted-p (record val) + (list 'bbdb-cache-set-deleted-p (list 'bbdb-record-cache record) val)) + +(defmacro bbdb-record-set-namecache (record newval) + (list 'bbdb-cache-set-namecache (list 'bbdb-record-cache record) newval)) + +(defmacro bbdb-record-set-sortkey (record newval) + (list 'bbdb-cache-set-sortkey (list 'bbdb-record-cache record) newval)) + +(defmacro bbdb-record-set-marker (record newval) + (list 'bbdb-cache-set-marker (list 'bbdb-record-cache record) newval)) + + +;; The "notes" and "properties" accessors don't need to be fast. + +(defun bbdb-record-notes (record) + (if (consp (bbdb-record-raw-notes record)) + (cdr (assq 'notes (bbdb-record-raw-notes record))) + (bbdb-record-raw-notes record))) + +;; this works on the 'company field as well. +(defun bbdb-record-getprop (record property) + (if (memq property '(name address addresses phone phones net aka AKA)) + (error "bbdb: cannot access the %s field this way" property)) + (if (eq property 'company) + (bbdb-record-company record) + (if (consp (bbdb-record-raw-notes record)) + (cdr (assq property (bbdb-record-raw-notes record))) + (if (and (eq property 'notes) + (stringp (bbdb-record-raw-notes record))) + (bbdb-record-raw-notes record) + nil)))) + +(defun bbdb-get-field (rec field &optional nn) + "Get the N-th element (or all if nil) of the notes FIELD of the REC. +If the note is absent, returns a zero length string." + (let ((note (or (bbdb-record-getprop rec field) ""))) + (if nn + (nth nn (split-string note " ,;\t\n\f\r\v")) + note))) + +;; this works on the 'company field as well. +(defun bbdb-record-putprop (record property newval) + (if (memq property '(name address addresses phone phones net aka AKA)) + (error "bbdb: cannot annotate the %s field this way" property)) + (if (eq property 'company) + (bbdb-record-set-company record + (bbdb-record-set-company record newval)) + (if (and (eq property 'notes) + (not (consp (bbdb-record-raw-notes record)))) + (bbdb-record-set-raw-notes record newval) + (or (listp (bbdb-record-raw-notes record)) + (bbdb-record-set-raw-notes record + (list (cons 'notes (bbdb-record-raw-notes record))))) + (let ((old (assq property (bbdb-record-raw-notes record)))) + (if old + (if newval + (setcdr old newval) + (bbdb-record-set-raw-notes record + (delq old (bbdb-record-raw-notes record)))) + (and newval + (bbdb-record-set-raw-notes record + (append (bbdb-record-raw-notes record) + (list (cons property newval)))))))) + ;; save some file space: if we ever end up with ((notes . "...")), + ;; replace it with the string. + (if (and (consp (bbdb-record-raw-notes record)) + (null (cdr (bbdb-record-raw-notes record))) + (eq 'notes (car (car (bbdb-record-raw-notes record))))) + (bbdb-record-set-raw-notes record + (cdr (car (bbdb-record-raw-notes record))))) + ) + ;; If we're changing the company, then we need to sort, since the company + ;; is the sortkey for nameless records. This should almost never matter... + (bbdb-change-record record (eq property 'company)) + newval) + +(defun bbdb-record-set-notes (record newval) + (if (consp (bbdb-record-raw-notes record)) + (bbdb-record-putprop record 'notes newval) + (bbdb-record-set-raw-notes record newval) + (bbdb-change-record record nil))) + +(defun bbdb-phone-string (phone) + (if (= 2 (length phone)) ; euronumbers.... + (aref phone 1) + ;; numbers should come in two forms: + ;; ["where" 415 555 1212 99] or ["where" "the number"] + (if (stringp (aref phone 1)) + (error "doubleplus ungood: euronumbers unwork")) + (concat (if (/= 0 (bbdb-phone-area phone)) + (format "(%03d) " (bbdb-phone-area phone)) + "") + (if (/= 0 (bbdb-phone-exchange phone)) + (format "%03d-%04d" + (bbdb-phone-exchange phone) (bbdb-phone-suffix phone)) + "") + (if (and (bbdb-phone-extension phone) + (/= 0 (bbdb-phone-extension phone))) + (format " x%d" (bbdb-phone-extension phone)) + "")))) + +;; Legacy function. Used to convert a zip datastructure string into a +;; formated string. As zip codes are plain strings now, use +;; `bbdb-address-zip' instead. +(defalias 'bbdb-address-zip-string 'bbdb-address-zip) + +(defmacro bbdb-record-lessp (record1 record2) + (list 'string< (list 'bbdb-record-sortkey record1) + (list 'bbdb-record-sortkey record2))) + +(defmacro bbdb-subint (string match-number) + (list 'string-to-int + (list 'substring string + (list 'match-beginning match-number) + (list 'match-end match-number)))) + +(eval-and-compile + (if (fboundp 'display-error) + (fset 'bbdb-display-error 'display-error) + (defun bbdb-display-error(msg stream) + (message "Error: %s" (nth 1 msg))))) + +(defmacro bbdb-error-retry (form) + (list 'catch ''--bbdb-error-retry-- + (list 'while ''t + (list 'condition-case '--c-- + (list 'throw ''--bbdb-error-retry-- form) + '(error + (ding) + (let ((cursor-in-echo-area t)) + (bbdb-display-error --c-- nil) + (sit-for 2))))))) + +;;; Completion on labels and field data + +;;; Realistically speaking, it doesn't make sense to offer minibuffer +;;; completion for some fields - like ones that don't have labels! +;;; +;;; Also, I could probably do this with macros similar to the +;;; def-struct stuff. +(defcustom bbdb-default-label-list + '("Home" "Office" "Mobile" "Other") + "*Default list of labels for Address and Phone fields." + :group 'bbdb-record-creation + :type '(repeat string)) + +(defcustom bbdb-phones-label-list + bbdb-default-label-list + "*List of labels for Phone field. +The default value is `bbdb-default-label-list'." + :group 'bbdb-record-creation + :type '(repeat string)) + +(defcustom bbdb-addresses-label-list + bbdb-default-label-list + "*List of labels for Address field. +The default value is `bbdb-default-label-list'." + :group 'bbdb-record-creation + :type '(repeat string)) + +(defun bbdb-label-completion-list (field) + "Figure out a completion list for the specified FIELD label. +This evaluates the variable bbdb-FIELD-label-list, such +as `bbdb-phones-label-list'." + (if (boundp (intern (format "bbdb-%s-label-list" field))) + (eval (intern (format "bbdb-%s-label-list" field))) + ;; special-case out the ones it doesn't make sense for here? + bbdb-default-label-list)) + +(defun bbdb-label-completion-default (field) + "Figure out a default label from the completion list for FIELD. +This evaluates the variable bbdb-default-FIELD-label, such +as `bbdb-default-phones-label', if it exists, or it takes +the first item from the list of completions for FIELD as +returned by `bbdb-label-completion-list'." + (if (boundp (intern (format "bbdb-default-%s-label" field))) + (eval (intern (format "bbdb-default-%s-label" field))) + (nth 0 (bbdb-label-completion-list field)))) + +;; These are so you can accumulate e.g. mail aliases or company names +;; and have BBDB offer completion on them. +(defun bbdb-data-completion-list (field) + "Figure out a completion list for the specified FIELD value. +This evaluates the variable bbdb-FIELD-data-list, such +as `bbdb-mail-alias-data-list', if it exists, or it uses +`bbdb-default-label-list'." + (if (boundp (intern (format "bbdb-%s-data-list" field))) + (eval (intern (format "bbdb-%s-data-list" field))) + ;; special-case out the ones it doesn't make sense for here? + bbdb-default-label-list)) + +(defun bbdb-data-completion-default (field) + "Figure out a default value from the completion list for FIELD. +This evaluates the variable bbdb-default-FIELD-data, such +as `bbdb-default-mail-alias-data', if it exists, or it takes +the first item from the list of completions for FIELD as +returned by `bbdb-data-completion-list'." + (if (boundp (intern (format "bbdb-default-%s-data" field))) + (eval (intern (format "bbdb-default-%s-data" field))) + (nth 0 (bbdb-label-completion-list field)))) + +;;; +(defvar bbdb-buffer nil) +(defun bbdb-buffer () + (if (and bbdb-buffer (buffer-live-p bbdb-buffer)) + bbdb-buffer + (when (and bbdb-file-remote + (file-newer-than-file-p bbdb-file-remote bbdb-file)) + (let ((coding-system-for-write bbdb-file-coding-system)) + (copy-file bbdb-file-remote bbdb-file t t))) + (setq bbdb-buffer (find-file-noselect bbdb-file 'nowarn)))) + +(defmacro bbdb-with-db-buffer (&rest body) + (cons 'with-current-buffer + (cons '(bbdb-buffer) + (if (and (boundp 'bbdb-debug) bbdb-debug) + ;; if we're debugging, and the .bbdb buffer is visible in + ;; a window, temporarilly switch to that window so that + ;; when we come out, that window has been scrolled to the + ;; record we've just modified. (make w-point = b-point) + (list + (list 'let '((w (and bbdb-debug + (get-buffer-window + (buffer-name + (get-buffer bbdb-file)))))) + (list 'save-excursion + (cons 'save-window-excursion + (cons '(and w (select-window w)) + body))))) + body)))) + +(defsubst bbdb-string-trim (string) + "Lose leading and trailing whitespace. Also remove all properties +from string." + (if (string-match "\\`[ \t\n]+" string) + (setq string (substring string (match-end 0)))) + (if (string-match "[ \t\n]+\\'" string) + (setq string (substring string 0 (match-beginning 0)))) + ;; This is not ideologically blasphemous. It is a bad function to + ;; use on regions of a buffer, but since this is our string, we can + ;; do whatever we want with it. --Colin + (set-text-properties 0 (length string) nil string) + string) + +(defun bbdb-read-string (prompt &optional default completions) + "Reads a string, trimming whitespace and text properties." + (bbdb-string-trim + (if completions + (completing-read prompt completions nil nil (cons default 0)) + (bbdb-string-trim (read-string prompt default))))) + +;;; Address formatting. + +(defcustom bbdb-time-display-format "%d %b %Y" + "The format for the timestamp to be used in the creation-date and +timestamp fields. See the documentation for `format-time-string'." + :group 'bbdb :type 'string) + +(defun bbdb-time-convert (date &optional format) + "Convert a date from the BBDB internal format to the format +determined by FORMAT (or `bbdb-time-display-format' if FORMAT not +present). Returns a string containing the date in the new format." + (let ((parts (bbdb-split date "-"))) + (format-time-string (or format bbdb-time-display-format) + (encode-time 0 0 0 (string-to-int (caddr parts)) + (string-to-int (cadr parts)) + (string-to-int (car parts)))))) + +(defalias 'bbdb-format-record-timestamp 'bbdb-time-convert) +(defalias 'bbdb-format-record-creation-date 'bbdb-time-convert) + +(defconst bbdb-gag-messages nil + "Bind this to t to quiet things down - do not set it!") + +(defconst bbdb-buffer-name "*BBDB*") + +(defcustom bbdb-display-layout-alist + '((one-line (order . (phones mail-alias net notes)) + (name-end . 24) + (toggle . t)) + (multi-line (omit . (creation-date timestamp)) + (toggle . t)) + (pop-up-multi-line) + (full-multi-line)) + "*An alist describing each display layout. +The format of an element is (LAYOUT-NAME OPTION-ALIST). + +By default there are four different layout types used by BBDB, which are +`one-line', `multi-line', `pop-up-multi-line' (used for pop-ups) and +`full-multi-line' (showing all fields of a record). + +OPTION-ALIST specifies the options for the layout. Valid options are: + + ------- Availability -------- + Format one-line multi-line default if unset +------------------------------------------------------------------------------ + (toggle . BOOL) + + nil + (order . FIELD-LIST) + + '(phones ...) + (omit . FIELD-LIST) + + nil + (name-end . INTEGER) + - 40 + (indentation . INTEGER) - + 14 + (primary . BOOL) - + nil + (test . SEXP) + + nil + +- toggle: controls if this layout is included when toggeling the display layout +- order: defines a user specific order for the fields, where `t' is a place + holder for all remaining fields +- omit: is a list of fields which should not be displayed or `t' to exclude all + fields except those listed in the order option +- name-end: sets the column where the name should end in one-line layout. +- indentation: sets the level of indentation for multi-line display. +- primary: controls wether only the primary net is shown or all are shown. +- test: a lisp expression controlling wether the record is to be displayed. + +When you add a new layout FOO, you can write a corresponding layout +function bbdb-format-record-layout-FOO. If you do not write your own +layout function, the multi-line layout will be used." + :group 'bbdb + :type + `(repeat + (cons :tag "Layout Definition" + (choice :tag "Layout type" + (const one-line) + (const multi-line) + (const pop-up-multi-line) + (const full-multi-line) + (symbol)) + (set :tag "Properties" + (cons :tag "Order" + (const :tag "List of fields to order by" order) + (repeat (choice (const phones) + (const addresses) + (const net) + (const AKA) + (const notes) + (symbol :tag "other") + (const :tag "Remaining fields" t)))) + (choice :tag "Omit" + :value (omit . nil) + (cons :tag "List of fields to omit" + (const :tag "Fields not to display" omit) + (repeat (choice (const phones) + (const addresses) + (const net) + (const AKA) + (const notes) + (symbol :tag "other")))) + (const :tag "Exclude all fields except those listed in the order property" t)) + (cons :tag "Indentation" + :value (indentation . 14) + (const :tag "Level of indentation for multi-line layout" + indentation) + (number :tag "Column")) + (cons :tag "End of name field" + :value (name-end . 24) + (const :tag "The column where the name should end in one-line layout" + name-end) + (number :tag "Column")) + (cons :tag "Toggle" + (const :tag "The layout is included when toggling display layout" toggle) + boolean) + (cons :tag "Primary Net Only" + (const :tag "Only the primary net address is included" primary) + boolean) + (cons :tag "Test" + (const :tag "Show only records passing this test" test) + (choice (const :tag "No test" nil) + (cons :tag "List of required fields" + (const :tag "Choose from the attributes in the following set:" and) + (set + (const name) + (const company) + (const net) + (const phones) + (const addresses) + (const notes))) + (sexp :tag "Lisp expression"))))))) + + +(defcustom bbdb-display-layout 'multi-line + "*The default display layout." + :group 'bbdb + :type '(choice (const one-line) + (const multi-line) + (const full-multi-line) + (symbol))) + +(defcustom bbdb-pop-up-display-layout 'pop-up-multi-line + "*The default display layout pop-up BBDB buffers, i.e. mail, news." + :group 'bbdb + :type '(choice (const one-line) + (const multi-line) + (const full-multi-line) + (symbol))) + +(defun bbdb-display-layout-get-option (layout option) + (let ((layout-spec (if (listp layout) + layout + (assoc layout bbdb-display-layout-alist))) + option-value) + (and layout-spec + (setq option-value (assoc option layout-spec)) + (cdr option-value)))) + +(defcustom bbdb-address-formatting-alist + '((bbdb-address-is-continental . bbdb-format-address-continental) + (nil . bbdb-format-address-default)) + "Alist of address identifying and address formatting functions. +The key is an identifying function which accepts an address. The +associated value is a formatting function which inserts the formatted +address in the current buffer. If the identifying function returns +non-nil, the formatting function is called. When nil is used as the +car, then the associated formatting function will always be called. +Therefore you should always have (nil . bbdb-format-address-default) as +the last element in the alist. + +All functions should take two arguments, the address and an indentation. +The indentation argument may be optional. + +This alist is used in `bbdb-format-address'. + +See also `bbdb-address-print-formatting-alist'." + :group 'bbdb-record-display + :type '(repeat (cons function function))) + +(defvar bbdb-address-print-formatting-alist) ; "bbdb-print" + +(defun bbdb-address-is-continental (addr) + "Return non-nil if the address ADDR is a continental address. +This is done by comparing the zip code to `bbdb-continental-zip-regexp'. + +This is a possible identifying function for +`bbdb-address-formatting-alist' and +`bbdb-address-print-formatting-alist'." + (string-match bbdb-continental-zip-regexp (bbdb-address-zip addr))) + +(defun bbdb-format-streets (addr indent) + "Insert street subfields of address ADDR in current buffer. +This may be used by formatting functions listed in +`bbdb-address-formatting-alist'." + (bbdb-mapc (lambda(str) + (indent-to indent) + (insert str "\n")) + (bbdb-address-streets addr))) + +(defun bbdb-format-address-continental (addr &optional indent) + "Insert formated continental address ADDR in current buffer. +This format is used in western Europe, for example. + +This function is a possible formatting function for +`bbdb-address-formatting-alist'. + +The result looks like this: + location: street + street + ... + zip city, state + country" + (setq indent (or indent 14)) + (let (;(fmt (format " %%%ds: " indent)) + (indent (+ 3 indent))) + ;(insert (format fmt (bbdb-address-location addr))) + (bbdb-format-streets addr indent) + (let ((c (bbdb-address-city addr)) + (s (bbdb-address-state addr)) + (z (bbdb-address-zip addr))) + (if (or (> (length c) 0) + (> (length z) 0) + (> (length s) 0)) + (progn + (indent-to indent) + (insert z (if (and (> (length z) 0) + (> (length c) 0)) " " "") + c (if (and (or (> (length z) 0) + (> (length c) 0)) + (> (length s) 0)) ", " "") + s "\n")))) + (let ((str (bbdb-address-country addr))) + (if (= 0 (length str)) nil + (indent-to indent) (insert str "\n"))))) + +(defun bbdb-format-address-default (addr &optional indent) + "Insert formated address ADDR in current buffer. +This is the default format; it is used in the US, for example. + +This function is a possible formatting function for +`bbdb-address-formatting-alist'. + +The result looks like this: + location: street + street + ... + city, state zip + country" + (setq indent (or indent 14)) + (let (;(fmt (format " %%%ds: " indent)) + (indent (+ 3 indent))) +; (insert (format fmt (bbdb-address-location addr))) + (bbdb-format-streets addr indent) + (let ((c (bbdb-address-city addr)) + (s (bbdb-address-state addr)) + (z (bbdb-address-zip addr))) + (if (or (> (length c) 0) + (> (length z) 0) + (> (length s) 0)) + (progn + (indent-to indent) + (insert c (if (and (> (length c) 0) + (> (length s) 0)) ", " "") + s (if (and (or (> (length c) 0) + (> (length s) 0)) + (> (length z) 0)) " " "") + z "\n")))) + (let ((str (bbdb-address-country addr))) + (if (= 0 (length str)) nil + (indent-to indent) (insert str "\n"))))) + +(defun bbdb-format-address (addr &optional printing indent) + "Call appropriate formatting function for address ADDR. + +If optional second argument PRINTING is non-nil, this uses the alist +`bbdb-address-print-formatting-alist' to determine how the address is to +formatted and inserted into the current buffer. This is used by +`bbdb-print-format-record'. + +If second argument PRINTING is nil, this uses the alist +`bbdb-address-formatting-alist' to determine how the address is to +formatted and inserted into the current buffer. This is used by +`bbdb-format-record'." + ;; alist contains functions ((ident1 . format1) (ident2 . format2) ...) + ;; the first identifying-function is (caar alist) + ;; the first formatting-function is (cdar alist) + (let ((alist (if printing bbdb-address-print-formatting-alist + bbdb-address-formatting-alist))) + ;; while there a functions left and the current function does not + ;; identify the address, try the next function. + (while (and (caar alist) + (null (funcall (caar alist) addr))) + (setq alist (cdr alist))) + ;; if we haven't reached the end of functions, we got a hit. + (when alist + (if printing + (funcall (cdar alist) addr) + (funcall (cdar alist) addr indent))))) + +(defun bbdb-format-record-name-company (record) + (let ((name (or (bbdb-record-name record) "???")) + (company (bbdb-record-company record)) + (start (point))) + + (insert name) + (put-text-property start (point) 'bbdb-field '(name)) + + (when company + (insert " - ") + (setq start (point)) + (insert company) + (put-text-property start (point) 'bbdb-field '(company))))) + +(defun bbdb-format-record-one-line-phones (layout record phone) + "Return a formatted phone number for one-line display." + (let ((start (point))) + (insert (format "%s " (aref phone 1))) + (put-text-property start (point) 'bbdb-field + (list 'phone phone (aref phone 0))) + (setq start (point)) + (insert (format "(%s)" (aref phone 0))) + (put-text-property start (point) 'bbdb-field + (list 'phone phone 'field-name)))) + +(defun bbdb-format-record-one-line-net (layout record net) + "Return a formatted list of nets for one-line display." + (let ((start (point))) + (insert net) + (put-text-property start (point) 'bbdb-field (list 'net net)))) + +(defun bbdb-format-record-layout-one-line (layout record field-list) + "Record formatting function for the one-line layout. +See `bbdb-display-layout-alist' for more." + ;; name and company + (bbdb-format-record-name-company record) + (let ((name-end (or (bbdb-display-layout-get-option layout 'name-end) + 40)) + start end) + (save-excursion + (setq end (point)) + (beginning-of-line) + (setq start (point))) + (when (> (- end start -1) name-end) + (put-text-property (+ start name-end -4) end 'invisible t) + (insert "...")) + ;; guarantee one space after name - company + (insert " ") + (indent-to name-end)) + ;; rest of the fields + (let (start field contentfun formatfun values value) + (while field-list + (setq field (car field-list) + contentfun (intern (concat "bbdb-record-" + (symbol-name field)))) + (if (fboundp contentfun) + (setq values (eval (list contentfun record))) + (setq values (bbdb-record-getprop record field))) + (when (and (eq field 'net) + (bbdb-display-layout-get-option layout 'primary)) + (setq values (list (car values)))) + (when values + (if (not (listp values)) (setq values (list values))) + (setq formatfun (intern (format "bbdb-format-record-%s-%s" + layout field))) + (while values + (setq start (point) + value (car values)) + (if (fboundp formatfun) + (funcall formatfun layout record value) + (insert (format "%s" value)) + (cond ((eq field 'addresses) + (put-text-property start (point) 'bbdb-field + (list 'address value))) + ((eq field 'phones) + (put-text-property start (point) 'bbdb-field + (list 'phone value))) + ((memq field '(name net aka)) + (put-text-property start (point) 'bbdb-field + (list field value ))) + (t + (put-text-property start (point) 'bbdb-field + (list 'property (list field value)))))) + (setq values (cdr values)) + (if values (insert ", "))) + (insert "; ")) + (setq field-list (cdr field-list)))) + ;; delete the trailing "; " + (backward-delete-char 2) + (insert "\n")) + +(defun bbdb-format-record-layout-multi-line (layout record field-list) + "Record formatting function for the multi-line layout. +See `bbdb-display-layout-alist' for more." + (bbdb-format-record-name-company record) + (insert "\n") + (let* ((notes (bbdb-record-raw-notes record)) + (indent (or (bbdb-display-layout-get-option layout 'indentation) 14)) + (fmt (format " %%%ds: " indent)) + start field) + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + (while field-list + (setq field (car field-list) + start (point)) + (cond ((eq field 'phones) + (let ((phones (bbdb-record-phones record)) + loc phone) + (while phones + (setq phone (car phones) + start (point)) + (setq loc (format fmt (bbdb-phone-location phone))) + (insert loc) + (put-text-property start (point) 'bbdb-field + (list 'phone phone 'field-name)) + (setq start (point)) + (insert (bbdb-phone-string phone) "\n") + (put-text-property start (point) 'bbdb-field + (list 'phone phone + (bbdb-phone-location phone))) + (setq phones (cdr phones)))) + (setq start nil)) + ((eq field 'addresses) + (let ((addrs (bbdb-record-addresses record)) + loc addr) + (while addrs + (setq addr (car addrs) + start (point)) + (setq loc (format fmt (bbdb-address-location addr))) + (insert loc) + (put-text-property start (point) 'bbdb-field + (list 'address addr 'field-name)) + (setq start (point)) + (bbdb-format-address addr nil indent) + (put-text-property start (point) 'bbdb-field + (list 'address addr + (bbdb-address-location addr))) + (setq addrs (cdr addrs)))) + (setq start nil)) + ((eq field 'net) + (let ((net (bbdb-record-net record))) + (when net + (insert (format fmt "net")) + (put-text-property start (point) 'bbdb-field + '(net field-name)) + (setq start (point)) + (if (bbdb-display-layout-get-option layout 'primary) + (insert (car net) "\n") + (insert (mapconcat (function identity) net ", ") "\n")) + (put-text-property start (point) 'bbdb-field '(net))))) + ((eq field 'aka) + (let ((aka (bbdb-record-aka record))) + (when aka + (insert (format fmt "AKA")) + (put-text-property start (point) 'bbdb-field + '(aka field-name)) + (insert (mapconcat (function identity) aka ", ") "\n") + (setq start (point)) + (put-text-property start (point) 'bbdb-field '(aka))))) + (t + (let ((note (assoc field notes)) + (indent (length (format fmt ""))) + p notefun) + (when note + (insert (format fmt field)) + (put-text-property start (point) 'bbdb-field + (list 'property note 'field-name)) + (setq start (point)) + (setq p (point) + notefun (intern (format "bbdb-format-record-%s" field))) + (if (fboundp notefun) + (insert (funcall notefun (cdr note))) + (insert (cdr note))) + (save-excursion + (save-restriction + (narrow-to-region p (1- (point))) + (goto-char (1+ p)) + (while (search-forward "\n" nil t) + (insert (make-string indent ?\ ))))) + (insert "\n")) + (put-text-property start (point) 'bbdb-field + (list 'property note))))) + (setq field-list (cdr field-list))))) + +(defalias 'bbdb-format-record-layout-full-multi-line + 'bbdb-format-record-layout-multi-line) + +(defalias 'bbdb-format-record-layout-pop-up-multi-line + 'bbdb-format-record-layout-multi-line) + +(defun bbdb-format-record (record &optional layout) + "Insert a formatted version of RECORD into the current buffer. + +LAYOUT can be a symbol describing a layout in +`bbdb-display-layout-alist'. For compatibility reasons, LAYOUT can +also be nil or t, where t stands for the one-line, and nil for the +multi-line layout." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: formatting deleted record"))) + (setq layout (cond ((eq nil layout) + 'multi-line) + ((eq t layout) + 'one-line) + ((symbolp layout) + layout) + (t + (error "Unknown layout `%s'" layout)))) + (let* ((layout-spec (assoc layout bbdb-display-layout-alist)) + (test (bbdb-display-layout-get-option layout-spec 'test)) + (omit-list (bbdb-display-layout-get-option layout-spec 'omit)) + (order-list (bbdb-display-layout-get-option layout-spec 'order)) + (all-fields (append '(phones addresses net aka) + (let ((raw-notes (bbdb-record-raw-notes record))) + (if (stringp raw-notes) + '(notes) + (mapcar (lambda (r) (car r)) raw-notes))))) + format-function field-list) + (when (or (not test) + ;; bind some variables for the test + (let ((name (bbdb-record-name record)) + (company (bbdb-record-company record)) + (net (bbdb-record-net record)) + (phones (bbdb-record-phones record)) + (addresses (bbdb-record-addresses record)) + (notes (bbdb-record-raw-notes record))) + ;; this must evaluate to non-nil if the record is to be shown + (eval test))) + (if (functionp omit-list) + (setq omit-list (funcall omit-list record layout))) + (if (functionp order-list) + (setq order-list (funcall order-list record layout))) + ;; first omit unwanted fields + (when (and omit-list (or (not order-list) (memq t order-list))) + (if (not (listp omit-list)) + ;; t => show nothing + (setq all-fields nil) + ;; listp => show all fields except those listed here + (while omit-list + (setq all-fields (delete (car omit-list) all-fields) + omit-list (cdr omit-list))))) + ;; then order them + (if (not order-list) + (setq field-list all-fields) + (if (not (memq t order-list)) + (setq field-list order-list) + (setq order-list (reverse order-list)) + (setq all-fields (delete nil (mapcar (lambda (f) + (if (memq f order-list) + nil + f)) + all-fields))) + (while order-list + (if (eq t (car order-list)) + (setq field-list (append all-fields field-list)) + (setq field-list (cons (car order-list) field-list))) + (setq order-list (cdr order-list))))) + ;; call the actual format function + (setq format-function + (intern (format "bbdb-format-record-layout-%s" layout))) + (if (functionp format-function) + (funcall format-function layout record field-list) + (bbdb-format-record-layout-multi-line layout record field-list))))) + +(defun bbdb-frob-mode-line (n) + (setq + ;; identification + mode-line-buffer-identification + (if (> n 0) + (list 24 (buffer-name) ": " + (list 10 (format "%d/%d" n (length (bbdb-records)))) + '(bbdb-showing-changed-ones " !!" " ")) + (list (buffer-name) ": Insidious Big Brother Database v" bbdb-version " " + mode-line-modified "-")) + ;; modified indicator + mode-line-modified + '(bbdb-readonly-p "--%%%%-" (bbdb-modified-p "--**-" "-----")))) + +(defun bbdb-display-records-1 (records &optional append layout) + (setq append (or append (bbdb-append-records-p))) + + (if (or (null records) + (consp (car records))) + nil + + ;; add layout and a marker to the local list of records + (setq layout (or layout bbdb-display-layout)) + (setq records (mapcar (lambda (x) + (list x layout (make-marker))) + records))) + + (let ((b (current-buffer)) + (temp-buffer-setup-hook nil) + (temp-buffer-show-hook nil) + (first (car (car records)))) + + (if bbdb-multiple-buffers (bbdb-pop-up-bbdb-buffer)) + + (with-output-to-temp-buffer bbdb-buffer-name + (set-buffer bbdb-buffer-name) + + ;; If append is set, clear the buffer, otherwise do clean up. + (unless append (bbdb-undisplay-records)) + + ;; If we're appending these records to the ones already displayed, + ;; then first remove any duplicates, and then sort them. + (if append + (let ((rest records)) + (while rest + (if (assq (car (car rest)) bbdb-records) + (setq records (delq (car rest) records))) + (setq rest (cdr rest))) + (setq records (append bbdb-records records)) + (setq records + (sort records + (lambda (x y) (bbdb-record-lessp (car x) (car y))))))) + (make-local-variable 'mode-line-buffer-identification) + (make-local-variable 'mode-line-modified) + (set (make-local-variable 'bbdb-showing-changed-ones) nil) + (let ((done nil) + (rest records) + (changed (bbdb-changed-records))) + (while (and rest (not done)) + (setq done (memq (car (car rest)) changed) + rest (cdr rest))) + (setq bbdb-showing-changed-ones done)) + (bbdb-frob-mode-line (length records)) + (and (not bbdb-gag-messages) + (not bbdb-silent-running) + (message "Formatting...")) + (bbdb-mode) + ;; this in in the *BBDB* buffer, remember, not the .bbdb buffer. + (set (make-local-variable 'bbdb-records) nil) + (setq bbdb-records records) + (let ((buffer-read-only nil) + prs) + (bbdb-debug (setq prs (bbdb-records))) + (setq truncate-lines t) + (while records + (bbdb-debug (if (not (memq (car (car records)) prs)) + (error "record doubleplus unpresent!"))) + (set-marker (nth 2 (car records)) (point)) + (bbdb-format-record (nth 0 (car records)) + (nth 1 (car records))) + (setq records (cdr records)))) + (and (not bbdb-gag-messages) + (not bbdb-silent-running) + (message "Formatting...done."))) + (set-buffer bbdb-buffer-name) + (if (and append first) + (let ((cons (assq first bbdb-records)) + (window (get-buffer-window (current-buffer)))) + (if window (set-window-start window (nth 2 cons))))) + (bbdbq) + ;; this doesn't really belong here, but it's convenient ... and when + ;; using electric display it would not be called otherwise. + (save-excursion (run-hooks 'bbdb-list-hook)) + (if bbdb-gui (bbdb-fontify-buffer)) + (set-buffer-modified-p nil) + (setq buffer-read-only t) + (set-buffer b))) + +(defun bbdb-undisplay-records () + (let ((bbdb-display-buffer (get-buffer bbdb-buffer-name))) + (if (bufferp bbdb-display-buffer) + (save-excursion + (set-buffer bbdb-display-buffer) + (setq bbdb-showing-changed-ones nil + mode-line-modified nil + bbdb-records nil + buffer-read-only nil) + (erase-buffer) + (setq buffer-read-only t) + (set-buffer-modified-p nil))))) + + ;;; Electric display stuff + +(defconst bbdb-inside-electric-display nil) +;; hack hack: a couple of specials that the electric stuff uses for state. +(defvar bbdb-electric-execute-me) +(defvar bbdb-electric-completed-normally) + +(defun electric-bbdb-display-records (records) + (require 'electric) + (let ((bbdb-electric-execute-me nil)) ; Hack alert! throw-to-execute sets this! + (let ((bbdb-inside-electric-display t) + buffer + bbdb-electric-completed-normally ; Hack alert! throw-to-execute sets this! + ) + (save-excursion + (save-window-excursion + (save-window-excursion (bbdb-display-records-1 records)) + (setq buffer (window-buffer (Electric-pop-up-window bbdb-buffer-name))) + (set-buffer buffer) + (if (not bbdb-gag-messages) + (message "<<< Press Space to bury the Insidious Big Brother Database list >>>")) + (catch 'Done + (while t + (catch 'Blow-off-the-error + (setq bbdb-electric-completed-normally nil) + (unwind-protect + (progn + (catch 'electric-bbdb-list-select + (Electric-command-loop 'electric-bbdb-list-select + "-> " t)) + (setq bbdb-electric-completed-normally t)) + ;; protected + (if bbdb-electric-completed-normally + (throw 'Done t) + (ding) + (message "BBDB-Quit") + (throw 'Blow-off-the-error t) + ))))) + (bury-buffer buffer)))) + (message " ") + (if bbdb-electric-execute-me + (eval bbdb-electric-execute-me))) + nil) + +(defun bbdb-electric-throw-to-execute (form-to-execute) + "Exit the `electric-command-loop' and evaluate the given form." + ;; Hack alert! These variables are bound only within the scope of + ;; bbdb-electric-display-records! + (if (not (boundp 'bbdb-electric-execute-me)) + (error "plusungood: electrical short")) + (setq bbdb-electric-execute-me form-to-execute + bbdb-electric-completed-normally t) + (throw 'electric-bbdb-list-select t)) + + +(defun bbdb-done-command () (interactive) + (throw 'electric-bbdb-list-select t)) + +(defun bbdb-bury-buffer () + (interactive) + (if bbdb-inside-electric-display + (bbdb-done-command) + (bury-buffer))) + +(defun bbdb-display-records (records &optional layout append) + (let ((bbdb-window (get-buffer-window bbdb-buffer-name))) + (if (and bbdb-electric-p + ;; never be electric if the buffer is already on screen. + (not bbdb-window)) + (progn + (define-key bbdb-mode-map " " 'bbdb-done-command) + (electric-bbdb-display-records records)) + (bbdb-display-records-1 records append layout) + ;; don't smash keybinding if they invoked `bbdb-display' + ;; from inside an electric loop. + (unless bbdb-inside-electric-display + (define-key bbdb-mode-map " " 'undefined)) + (if (and (not bbdb-gag-messages) + (not bbdb-window)) + (message + (substitute-command-keys + (if (one-window-p t) + (if pop-up-windows + "Type \\[delete-other-windows] to unshow the bbdb-list window." + "Type \\[switch-to-buffer] RET to unshow the bbdb-list window.") + "Type \\[switch-to-buffer-other-window] RET to restore old contents of the bbdb-list window."))))))) + +(defun bbdbq () + (if (not (zerop (logand (random) 31))) nil + (let ((v '["\104\157\156\47\164\40\163\165\163\160\145\143\164\40\171\157\ +\165\162\40\156\145\151\147\150\142\157\162\72\40\162\145\160\157\162\164\40\ +\150\151\155\41" "\146\156\157\162\144" "\103\157\156\163\165\155\145\40\55\55\ +\40\102\145\40\123\151\154\145\156\164\40\55\55\40\104\151\145" "\114\157\166\ +\145\40\102\151\147\40\102\162\157\164\150\145\162" "\114\145\145\40\110\141\ +\162\166\145\171\40\117\163\167\141\154\144\40\141\143\164\145\144\40\141\154\ +\157\156\145" "\101\114\114\40\131\117\125\122\40\102\101\123\105\40\101\122\ +\105\40\102\105\114\117\116\107\40\124\117\40\125\123" "\127\141\162\40\151\ +\163\40\120\145\141\143\145" "\106\162\145\145\144\157\155\40\151\163\40\123\ +\154\141\166\145\162\171" "\111\147\156\157\162\141\156\143\145\40\151\163\40\ +\123\164\162\145\156\147\164\150" "\120\162\157\154\145\163\40\141\156\144\40\ +\141\156\151\155\141\154\163\40\141\162\145\40\146\162\145\145"])) + (message (aref v (% (logand 255 (random)) (length v)))) + (message " ")))) + +(defmacro bbdb-hashtable () + '(bbdb-with-db-buffer (bbdb-records nil t) bbdb-hashtable)) + +(defun bbdb-changed-records () + (bbdb-with-db-buffer (bbdb-records nil t) bbdb-changed-records)) + +(defmacro bbdb-build-name (f l) + (list 'downcase + (list 'if (list '= (list 'length f) 0) l + (list 'if (list '= (list 'length l) 0) f + (list 'concat f " " l))))) + +(defun bbdb-remove! (e l) + (if (null l) l + (let ((ret l) + (n (cdr l))) + (while n + (if (eq e (car n)) + (setcdr l (cdr n)) ; skip n + (setq l n)) ; keep n + (setq n (cdr n))) + (if (eq e (car ret)) (cdr ret) + ret)))) + +(defun bbdb-remove-memq-duplicates (l) + (let (ret tail) + (setq ret (cons '() '()) + tail ret) + (while l + (if (not (memq (car l) ret)) + (setq tail (setcdr tail (cons (car l) '())))) + (setq l (cdr l))) + (cdr ret))) + +(defmacro bbdb-gethash (name &optional ht) + (list 'symbol-value + (list 'intern-soft name + (or ht '(bbdb-hashtable))))) + +(defmacro bbdb-puthash (name record &optional ht) + (list 'let (list (list 'sym (list 'intern name (or ht '(bbdb-hashtable))))) + (list 'set 'sym (list 'cons record + '(and (boundp sym) (symbol-value sym)))))) + +(defmacro bbdb-remhash (name record &optional ht) + (list 'let (list (list 's (list 'intern-soft name + (or ht '(bbdb-hashtable))))) + (list 'and 's (list 'set 's (list 'bbdb-remove! record + (list 'symbol-value 's)))))) + +(defsubst bbdb-search-intertwingle (name net) + "Find bbdb records matching NAME and NET. + +This is a more stringent version of bbdb-search-simple, which I am +not inclined to modify for fear of damaging other code that currently +relies on it. BBDB internals should be migrated to use this function +to identify which record is referred to by a name/net combination, +since search-simple has been overloaded with other functionality. + +The name comes from +http://www.mozilla.org/blue-sky/misc/199805/intertwingle.html, which +any budding BBDB hacker should be at least vaguely familiar with." + (bbdb-records t) + (if name (setq name (downcase name))) + (if net (setq net (downcase net)) + (setq net "")) + (let ((net-recs (bbdb-gethash (downcase net))) + recs) + (while net-recs + (if (or (and (not name) net) + (string= name (downcase (bbdb-record-name (car net-recs))))) + (add-to-list 'recs (car net-recs))) + (setq net-recs (cdr net-recs))) + recs)) + +(defsubst bbdb-search-simple (name net) + "name is a string; net is a string or list of strings." + (if (eq 0 (length name)) (setq name nil)) + (if (eq 0 (length net)) (setq net nil)) + (bbdb-records t) ; make sure db is parsed; don't check disk (faster) + (let ((name-recs (if name ;; filter out companies from hash + (let ((recs (bbdb-gethash (downcase name))) + answer) + (while recs + (let ((n-rec (car recs))) + (if (string= (downcase name) + (downcase + (or (bbdb-record-name + n-rec) + (bbdb-record-company + n-rec) + ""))) + (setq answer (append recs (list n-rec)))) + (setq recs (cdr recs)))) + answer))) + (net-recs (if (stringp net) (bbdb-gethash (downcase net)) + (let (answer) + (while (and net (null answer)) + (setq answer (bbdb-gethash (downcase (car net))) + net (cdr net))) + answer))) + ret) + (if (not (and name-recs net-recs)) + (or (and name-recs (car name-recs)) + (and net-recs (car net-recs))) + + (while name-recs + (let ((name-rec (car name-recs)) + (nets net-recs)) + (while nets + (if (eq (car nets) name-rec) + (setq nets '() + name-recs '() + ret name-rec) + (setq nets (cdr nets)))) + (if name-recs (setq name-recs (cdr name-recs)) + name-rec))) + ret))) + +(defun bbdb-net-convert (record) + "Given a record whose net field is a comma-separated string, convert it to +a list of strings (the new way of doing things.) Returns the new list." + (bbdb-record-set-net record (bbdb-split (bbdb-record-net record) ","))) + +(defun bbdb-split (string separators) + "Return a list by splitting STRING at SEPARATORS. +The inverse function of `bbdb-join'." + (let (result + (not-separators (concat "^" separators))) + (save-excursion + (set-buffer (get-buffer-create " *split*")) + (erase-buffer) + (insert string) + (goto-char (point-min)) + (while (progn + (skip-chars-forward separators) + (skip-chars-forward " \t\n\r") + (not (eobp))) + (let ((begin (point)) + p) + (skip-chars-forward not-separators) + (setq p (point)) + (skip-chars-backward " \t\n\r") + (setq result (cons (buffer-substring begin (point)) result)) + (goto-char p))) + (erase-buffer)) + (nreverse result))) + +(defun bbdb-join (list separator) + "Join a LIST to a string where the list elements are separated by SEPARATOR. +The inverse function of `bbdb-split'." + (when list + (mapconcat 'identity list separator))) + +(defsubst bbdb-hash-record (record) + "Insert the record in the appropriate hashtables. This must be called +while the .bbdb buffer is selected." + (let ((name (bbdb-record-name-1 record)) ; faster version + (company (bbdb-record-company record)) + (aka (bbdb-record-aka record)) + (net (bbdb-record-net record))) + (if (> (length name) 0) + (bbdb-puthash (downcase name) record bbdb-hashtable)) + (if (> (length company) 0) + (bbdb-puthash (downcase company) record bbdb-hashtable)) + (while aka + (bbdb-puthash (downcase (car aka)) record bbdb-hashtable) + (setq aka (cdr aka))) + (while net + (bbdb-puthash (downcase (car net)) record bbdb-hashtable) + (setq net (cdr net))))) + + +;;; Reading the BBDB + +(defvar inside-bbdb-records nil + "Internal variable. Do not touch.") + +(defvar bbdb-write-file-hooks '(bbdb-write-file-hook-fn) + "*The list of functions added to `local-write-file-hooks' in `bbdb-file'.") + +(defun bbdb-records (&optional dont-check-disk already-in-db-buffer) + "Return a list of all bbdb records; read in and parse the db if necessary. +This also notices if the disk file has changed out from under us, unless +optional arg DONT-CHECK-DISK is non-nil (which is faster, but hazardous.)" + (if inside-bbdb-records + (let ((debug-on-error t)) + (error "catastrophic: bbdb-records recursed"))) + (let ((inside-bbdb-records t) + (buf (if already-in-db-buffer (current-buffer) (bbdb-buffer))) + shut-up) + (with-current-buffer buf + ;; make sure the BBDB in memory is not out of synch with disk. + (cond (dont-check-disk nil) + ((verify-visited-file-modtime buf) nil) + ((and bbdb-auto-revert-p (not (buffer-modified-p buf))) + (message "BBDB has changed on disk, reverting...") + (setq shut-up t) + (revert-buffer t t)) + ;; hassle the user + ((bbdb-yes-or-no-p + (if (buffer-modified-p buf) + "BBDB has changed on disk; flush your changes and revert? " + "BBDB has changed on disk; revert? ")) + (or (file-exists-p bbdb-file) + (error "bbdb: file %s no longer exists!!" bbdb-file)) + (revert-buffer t t)) + ;; this is the case where the .bbdb file has changed; the buffer + ;; has changed as well; and the user has answered "no" to the + ;; "flush your changes and revert" question. The only other + ;; alternative is to save the file right now. If they answer + ;; no to the following question, they will be asked the + ;; preceeding question again and again some large (but finite) + ;; number of times. `bbdb-records' is called a lot, you see... + ((buffer-modified-p buf) + ;; this prompts + (bbdb-save-db t t)) + ;; otherwise, the buffer and file are inconsistent, but we let + ;; them stay that way. + ) + (unless (assq 'bbdb-records (buffer-local-variables)) + (set (make-local-variable 'bbdb-records) nil) + (set (make-local-variable 'bbdb-changed-records) nil) + (set (make-local-variable 'bbdb-end-marker) nil) + (set (make-local-variable 'bbdb-hashtable) nil) + (set (make-local-variable 'bbdb-propnames) nil) + (set (make-local-variable 'revert-buffer-function) + 'bbdb-revert-buffer) + (bbdb-mapc (lambda (ff) (add-hook 'local-write-file-hooks ff)) + bbdb-write-file-hooks) + (setq bbdb-hashtable (make-vector bbdb-hashtable-size 0))) + (setq bbdb-modified-p (buffer-modified-p) + buffer-read-only bbdb-readonly-p) + (or bbdb-records + (cond ((= (point-min) (point-max)) ; special-case empty db + ;; this doesn't need to be insert-before-markers because + ;; there are no db-markers in this buffer. + (insert (format ";; -*-coding: %s;-*-\n;;; file-version: %d\n" + bbdb-file-coding-system bbdb-file-format)) + (bbdb-flush-all-caches) + (setq bbdb-end-marker (point-marker)) + ;;(run-hooks 'bbdb-after-read-db-hook) ; run this? + nil) + (t + (or shut-up bbdb-silent-running (message "Parsing BBDB...")) + (bbdb-flush-all-caches) + (cond ((and bbdb-notice-auto-save-file + (file-newer-than-file-p (make-auto-save-file-name) + buffer-file-name)) + (if (bbdb-yes-or-no-p "BBDB auto-save file is newer; recover it? ") + (progn + (recover-file buffer-file-name) + (bury-buffer (current-buffer)) ; recover-file selects it + (auto-save-mode 1) ; turn autosave back on + (delete-file (make-auto-save-file-name)) + (message "Auto-save mode is ON in BBDB buffer. Suggest you save it soon.") + (sleep-for 2)) + ;; delete auto-save anyway, so we don't keep asking. + (condition-case nil + (delete-file (make-auto-save-file-name)) + (file-error nil))) + ;; tail-recurse and try again + (let ((inside-bbdb-records nil)) + (bbdb-records))) + (t + ;; normal case + (fillarray bbdb-hashtable 0) + (parse-bbdb-internal))))))))) + +(defun bbdb-revert-buffer (arg noconfirm) + ;; The .bbdb file's revert-buffer-function. + ;; Don't even think of calling this. + (kill-all-local-variables) ; clear db and caches. + (if (get-buffer bbdb-buffer-name) ; now contains invalid records; nukem. + (bbdb-undisplay-records)) + (let ((revert-buffer-function nil)) ; don't loop. + (revert-buffer arg noconfirm))) + +(defun parse-bbdb-internal () + (bbdb-debug (message "Parsing BBDB... (reading...)")) + (widen) + (goto-char (point-min)) + ;; go to the point at which the first record begins + (cond ((eq (following-char) ?\[) nil) + ((search-forward "\n[" nil 0) (forward-char -1)) + (t nil)) ;; no records + ;; look backwards for user-defined field names (for completion purposes.) + (save-excursion + (if (re-search-backward "^;+[ \t]*user-fields:[ \t]*\(" nil t) + (progn + (goto-char (1- (match-end 0))) + (setq bbdb-propnames + (mapcar (lambda (x) (list (symbol-name x))) + (read (point-marker))))))) + ;; look backwards for file version, and convert if necessary. + ;; (at least, I'll write this code if I ever change the file format again...) + (let ((v (save-excursion + (if (re-search-backward + "^;+[ \t]*file-version:[ \t]*\\([0-9]+\\)[ \t]*$" nil t) + (car (read-from-string + (buffer-substring + (match-beginning 1) (match-end 1)))))))) + (if (null v) ; current version, but no file-version: line. Bootstrap it. + (let ((modp (buffer-modified-p))) + ;; This should never happen (not any more, anyway...) + (bbdb-debug (error "bbdb corrupted: no file-version line")) + (setq v 2) + (save-excursion + (if (re-search-backward "^;" nil t) + (forward-line 1) + (goto-char 1)) + ;; remember, this goes before the begin-marker of the first + ;; record in the database! + (insert-before-markers + (format ";; -*-coding: %s;-*-\n;;; file-version: %d\n" + bbdb-file-coding-system bbdb-file-format))) + (set-buffer-modified-p modp))) + (cond ((< v bbdb-file-format) + (if bbdb-file-format-migration + ;; Sanity checking. + (if (/= (car bbdb-file-format-migration) v) + (error + (format + "BBDB file format has changed on disk from %d to %d!" + (car bbdb-file-format-migration) v))) + (setq bbdb-file-format-migration + (cons v (bbdb-migration-query v))))) + ((> v bbdb-file-format) + (error "BBDB version %s doesn't understand file format version %s." + bbdb-version v)) + (t (setq bbdb-file-format-migration (cons bbdb-file-format + bbdb-file-format))))) + ;; A trap to catch a bug + ;;(assert (not (null (car bbdb-file-format-migration)))) + + (bbdb-debug + (or (eobp) (looking-at "[\[]") + (error "no following bracket: bbdb corrupted")) + (if (save-excursion + (save-restriction + (widen) + (save-excursion (search-backward "\n[" nil t)))) + (error "bbdb corrupted: records before point"))) + + ;; Migrate only if we need to. Change the .bbdb buffer only if it + ;; is not to be saved in the newest version. + (if (= (car bbdb-file-format-migration) bbdb-file-format) + (parse-bbdb-frobnicate (parse-bbdb-read)) + (let ((newrecs (parse-bbdb-frobnicate (bbdb-migrate (parse-bbdb-read))))) + (cond ((= (cdr bbdb-file-format-migration) bbdb-file-format) + (bbdb-migrate-rewrite-all nil newrecs) + (bbdb-migrate-update-file-version + (car bbdb-file-format-migration) + (cdr bbdb-file-format-migration)))) + newrecs))) + +(defun parse-bbdb-read () + ;; narrow the buffer to skip over the rubbish before the first record. + (narrow-to-region (point) (point-max)) + (let ((records nil)) + ;; insert parens so we can read the db in one fell swoop (down in C). + (let ((buffer-read-only nil) + (modp (buffer-modified-p)) + ;; Make sure those parens get cleaned up. + ;; This code had better stay simple! + (inhibit-quit t)) + (goto-char (point-min)) (insert "(\n") + (goto-char (point-max)) (insert "\n)") + (goto-char (point-min)) + (setq records (read (current-buffer))) + (goto-char (point-min)) (delete-char 2) + (goto-char (point-max)) (delete-char -2) + (set-buffer-modified-p modp)) + records)) + +(defun parse-bbdb-frobnicate (records) + ;; now we have to come up with a marker for each record. Rather than + ;; calling read for each record, we read them at once (already done) and + ;; assume that the markers are at each newline. If this isn't the case, + ;; things can go *very* wrong. + (goto-char (point-min)) + (while (looking-at "[ \t\n\f]*;") + (forward-line 1)) + (widen) + (bbdb-debug (message "Parsing BBDB... (frobnicating...)")) + (setq bbdb-records records) + (let* ((head (cons '() records)) + (rest head) + record) + (while (cdr rest) + (setq record (car (cdr rest))) + ;; yow, are we stack-driven yet?? Damn byte-compiler... + ;; Make a cache. Put it in the record. Put a marker in the cache. + ;; Add record to hash tables. + (bbdb-cache-set-marker + (bbdb-record-set-cache record (make-vector bbdb-cache-length nil)) + (point-marker)) + (forward-line 1) + + ;; frob the label completion lists (and data completion when I, + ;; uh, get around to it, maybe. this stuff should probably be + ;; conditional, in case you're not running a 42GHz Pentium 69 + ;; with chrome tailpipes) + (let ((ps (bbdb-record-phones record)) + (pl (bbdb-label-completion-list "phones")) + (as (bbdb-record-addresses record)) + (al (bbdb-label-completion-list "addresses"))) + (while ps + (let ((l (bbdb-phone-location (car ps)))) + (or (member l pl) + (setq bbdb-phones-label-list + (append (or bbdb-phones-label-list + bbdb-default-label-list) + (list l)) + pl bbdb-phones-label-list))) + (setq ps (cdr ps))) + ;; Yes, I cut and pasted. + (while as + (let ((l (bbdb-address-location (car as)))) + (or (member l al) + (setq bbdb-addresses-label-list + (append (or bbdb-addresses-label-list + bbdb-default-label-list) + (list l)) + al bbdb-addresses-label-list))) + (setq as (cdr as)))) + + (if bbdb-no-duplicates-p + ;; warn the user that there is a duplicate... + (let* ((name (bbdb-record-name record)) + (tmp (and name (bbdb-gethash (downcase name) + bbdb-hashtable)))) + (if tmp (message "Duplicate BBDB record encountered: %s" name)))) + + (bbdb-hash-record record) + (setq rest (cdr rest)) + + (bbdb-debug + (if (and (cdr rest) (not (looking-at "[\[]"))) + (error "bbdb corrupted: junk between records at %s" (point))))) + ;; In case we removed some of the leading entries... + (setq bbdb-records (cdr head))) + ;; all done. + (setq bbdb-end-marker (point-marker)) + (run-hooks 'bbdb-after-read-db-hook) + (bbdb-debug (message "Parsing BBDB... (frobnicating...done)")) + bbdb-records) + +(defmacro bbdb-user-mail-names () + "Returns a regexp matching the address of the logged-in user." + '(or bbdb-user-mail-names + (setq bbdb-user-mail-names + (concat "\\b" (regexp-quote (user-login-name)) "\\b")))) + +(defun bbdb-write-file-hook-fn () + "This is just for `bbdb-write-file-hooks'. Keep it there." + ;; this is premature as the file isn't actually written yet; but it's just + ;; for the benefit of the mode-line of the *BBDB* buffer, and there isn't + ;; an after-write-file-hook, so it'll do. + (save-restriction + (widen) + (goto-char (point-min)) + ;; Fixme: probably this should check any existing cookie for + ;; consistency with bbdb-file-coding-system. + (unless (looking-at ";; *-\\*-coding:") + (insert-before-markers (format ";; -*-coding: %s;-*-\n" + bbdb-file-coding-system)))) + (setq bbdb-modified-p nil + bbdb-changed-records nil) + (let ((buf (get-buffer bbdb-buffer-name))) + (when buf + (with-current-buffer buf + (setq bbdb-showing-changed-ones nil) + (set-buffer-modified-p nil)))) + (when (and bbdb-file-remote + (or bbdb-file-remote-save-always + (y-or-n-p (format "Save the remote BBDB file %s too? " + bbdb-file-remote)))) + ;; write the current buffer, which is `bbdb-file' (since this is called + ;; from its `local-write-file-hooks'), into the `bbdb-file-remote'. + (let ((coding-system-for-write bbdb-file-coding-system)) + (write-region (point-min) (point-max) bbdb-file-remote)))) + +(defun bbdb-delete-record-internal (record) + (if (null (bbdb-record-marker record)) (error "bbdb: marker unpresent")) + (bbdb-with-db-buffer + (if (or bbdb-suppress-changed-records-recording + (memq record bbdb-changed-records)) + nil + (setq bbdb-changed-records (cons record bbdb-changed-records))) + (let ((tail (memq record bbdb-records))) + (if (null tail) (error "bbdb: unfound %s" record)) + (setq bbdb-records (delq record bbdb-records)) + (delete-region (bbdb-record-marker record) + (if (cdr tail) + (bbdb-record-marker (car (cdr tail))) + bbdb-end-marker)) + (let ((name (bbdb-record-name record)) + (company (bbdb-record-company record)) + (aka (bbdb-record-aka record)) + (nets (bbdb-record-net record))) + (if (> (length name) 0) + (bbdb-remhash (downcase name) record bbdb-hashtable)) + (if (> (length company) 0) + (bbdb-remhash (downcase company) record bbdb-hashtable)) + (while nets + (bbdb-remhash (downcase (car nets)) record bbdb-hashtable) + (setq nets (cdr nets))) + (while aka + (bbdb-remhash (downcase (car aka)) record bbdb-hashtable) + (setq aka (cdr aka))) + ) + (bbdb-record-set-sortkey record nil) + (setq bbdb-modified-p t)))) + +(defun bbdb-insert-sorted (record records) + "Inserts the RECORD into the list of RECORDS, in order. +Assumes the list is already sorted. Returns the new head." + (bbdb-debug (if (memq record records) + (error "doubleplus ununique: - %s" record))) + (let* ((rest (cons nil records)) + (top rest)) + (while (and (cdr rest) + (bbdb-record-lessp (nth 1 rest) record)) + (setq rest (cdr rest))) + (setcdr rest (cons record (cdr rest))) + (cdr top))) + +(defun bbdb-insert-record-internal (record unmigrated) + (if (null (bbdb-record-marker record)) + (bbdb-record-set-marker record (make-marker))) + (bbdb-with-db-buffer + (if (or bbdb-suppress-changed-records-recording + (memq record bbdb-changed-records)) + nil + (setq bbdb-changed-records (cons record bbdb-changed-records))) + (let ((print-escape-newlines t)) + (bbdb-record-set-sortkey record nil) ; just in case... + (setq bbdb-records + (bbdb-insert-sorted record bbdb-records)) + (let ((next (car (cdr (memq record bbdb-records))))) + (goto-char (if next + (bbdb-record-marker next) + bbdb-end-marker)) + ;; before printing the record, remove the cache \(we don't want that + ;; written to the file.\) Ater writing, put the cache back and update + ;; the cache's marker. + (let ((cache (bbdb-record-cache record)) + (point (point))) + (bbdb-debug + (if (= point (point-min)) + (error "doubleplus ungood: inserting at point-min (%s)" point)) + (if (and (/= point bbdb-end-marker) + (not (looking-at "[\[]"))) + (error "doubleplus ungood: not inserting before a record (%s)" + point))) + (bbdb-record-set-cache record nil) + (if unmigrated (bbdb-record-set-cache unmigrated nil)) + (insert-before-markers (prin1-to-string (or unmigrated record)) "\n") + (set-marker (bbdb-cache-marker cache) point) + (bbdb-record-set-cache record cache) +;; (if (bbdb-record-name record) +;; (bbdb-puthash (downcase (bbdb-record-name record)) record bbdb-hashtable)) +;; (let ((nets (bbdb-record-net record))) +;; (while nets +;; (bbdb-puthash (downcase (car nets)) record bbdb-hashtable) +;; (setq nets (cdr nets)))) + ;; This is marginally slower because it rebuilds the namecache, + ;; but it makes jbw's life easier. :-\) + (bbdb-hash-record record)) + record)) + (setq bbdb-modified-p t))) + +(defun bbdb-overwrite-record-internal (record unmigrated) + (bbdb-with-db-buffer + (if (or bbdb-suppress-changed-records-recording + (memq record bbdb-changed-records)) + nil + (setq bbdb-changed-records (cons record bbdb-changed-records))) + (let ((print-escape-newlines t) + (tail bbdb-records)) + ;; Look for record after RECORD in the database. Use the + ;; beginning marker of this record (or the marker for the end of + ;; the database if no next record) to determine where to stop + ;; deleting old copy of record + (while (and tail (not (eq record (car tail)))) + (setq tail (cdr tail))) + (if (null tail) (error "bbdb: unfound %s" record)) + (let ((cache (bbdb-record-cache record))) + + (bbdb-debug + (if (<= (bbdb-cache-marker cache) (point-min)) + (error "doubleplus ungood: cache marker is %s" + (bbdb-cache-marker cache))) + (goto-char (bbdb-cache-marker cache)) + (if (and (/= (point) bbdb-end-marker) + (not (looking-at "[\[]"))) + (error "doubleplus ungood: not inserting before a record (%s)" + (point)))) + + (goto-char (bbdb-cache-marker cache)) + (bbdb-record-set-cache record nil) + (if unmigrated (bbdb-record-set-cache unmigrated nil)) + + (insert (prin1-to-string (or unmigrated record)) "\n") + (delete-region (point) + (if (cdr tail) + (bbdb-record-marker (car (cdr tail))) + bbdb-end-marker)) + (bbdb-record-set-cache record cache) + + (bbdb-debug + (if (<= (if (cdr tail) + (bbdb-record-marker (car (cdr tail))) + bbdb-end-marker) + (bbdb-record-marker record)) + (error "doubleplus ungood: overwrite unworks"))) + + (setq bbdb-modified-p t) + record)))) + +(defvar inside-bbdb-change-record nil "hands off") +(defvar inside-bbdb-notice-hook nil + "Internal variable; hands off. +Set to t by the BBDB when inside the `bbdb-notice-hook'. + +Calls to the `bbdb-change-hook' are suppressed when this is non-nil.") + +(defun bbdb-change-record (record need-to-sort) + "Update the database after a change to the given record. Second arg +NEED-TO-SORT is whether the name has changed. You still need to worry +about updating the name hash-table." + (if inside-bbdb-change-record + record + (let ((inside-bbdb-change-record t) + unmigrated) + (or inside-bbdb-notice-hook + (bbdb-invoke-hook 'bbdb-change-hook record)) + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "bbdb: changing deleted record"))) + (if (/= (cdr bbdb-file-format-migration) bbdb-file-format) + (bbdb-unmigrate-record (setq unmigrated (bbdb-copy-thing record)))) + ;; Do the changing + (if (memq record (bbdb-records)) ; checks file synchronization too. + (if (not need-to-sort) ;; If we don't need to sort, overwrite it. + (progn + (bbdb-overwrite-record-internal record unmigrated) + (bbdb-debug + (if (not (memq record (bbdb-records))) + (error "Overwrite in change doesn't work")))) + ;; Since we do need to sort, delete then insert + (bbdb-delete-record-internal record) + (bbdb-debug + (if (memq record (bbdb-records)) + (error "Delete in need-sort change doesn't work"))) + (bbdb-insert-record-internal record unmigrated) + (bbdb-debug + (if (not (memq record (bbdb-records))) + (error "Insert in need-sort change doesn't work")))) + ;; Record isn't in database so add it. + (bbdb-insert-record-internal record unmigrated) + (bbdb-debug (if (not (memq record (bbdb-records))) + (error "Insert in change doesn't work")))) + (setq bbdb-modified-p t) + (bbdb-invoke-hook 'bbdb-after-change-hook record) + record))) + +(defun bbdb-copy-thing (thing) + "Copy a thing. Handles vectors, strings, markers, numbers, conses, +lists, symbols, and nil. Raises an error if it finds something it +doesn't know how to deal with." + (cond ((vectorp thing) + (let ((i 0) + (newvec (make-vector (length thing) nil))) + (while (< i (length thing)) + (aset newvec i (bbdb-copy-thing (aref thing i))) + (setq i (1+ i))) + newvec)) + ((stringp thing) + (copy-sequence thing)) + ((markerp thing) + (copy-marker thing)) + ((numberp thing) + thing) + ((consp thing) + (cons (bbdb-copy-thing (car thing)) + (bbdb-copy-thing (cdr thing)))) + ((listp thing) + (let ((i 0) newlist) + (while (< i (length thing)) + (setq newlist (append newlist (list (bbdb-copy-thing + (nth i thing)))) + i (1+ i))) + newlist)) + ((symbolp thing) + thing) + ((eq nil thing) + nil) + (t + (error "Don't know how to copy %s" (prin1-to-string thing))))) + +(defmacro bbdb-propnames () + '(bbdb-with-db-buffer bbdb-propnames)) + +(defun bbdb-set-propnames (newval) + (bbdb-with-db-buffer + (setq bbdb-propnames newval) + (widen) + (goto-char (point-min)) + (and (not (eq (following-char) ?\[)) + (search-forward "\n[" nil 0)) + (if (re-search-backward "^[ \t]*;+[ \t]*user-fields:[ \t]*\(" nil t) + (progn + (goto-char (1- (match-end 0))) + (delete-region (point) (progn (end-of-line) (point)))) + (and (re-search-backward "^[ \t]*;.*\n" nil t) + (goto-char (match-end 0))) + ;; remember, this goes before the begin-marker of the first + ;; record in the database! + (insert-before-markers ";;; user-fields: \n") + (forward-char -1)) + (prin1 (mapcar (lambda (x) (intern (car x))) + bbdb-propnames) + (current-buffer)) + bbdb-propnames)) + + +;;; BBDB mode + +(defun bbdb-mode () + "Major mode for viewing and editing the Insidious Big Brother Database. +Letters no longer insert themselves. Numbers are prefix arguments. +You can move around using the usual cursor motion commands. +\\ +\\[bbdb-add-or-remove-mail-alias]\t Add new mail alias to visible records or \ +remove it. +\\[bbdb-edit-current-field]\t Edit the field on the current line. +\\[bbdb-record-edit-notes]\t Edit the `notes' field for the current record. +\\[bbdb-delete-current-field-or-record]\t Delete the field on the \ +current line. If the current line is the\n\t first line of a record, then \ +delete the entire record. +\\[bbdb-insert-new-field]\t Insert a new field into the current record. \ +Note that this\n\t will let you add new fields of your own as well. +\\[bbdb-transpose-fields]\t Swap the field on the current line with the \ +previous field. +\\[bbdb-dial]\t Dial the current phone field. +\\[bbdb-next-record], \\[bbdb-prev-record]\t Move to the next or the previous \ +displayed record, respectively. +\\[bbdb-create]\t Create a new record. +\\[bbdb-toggle-records-display-layout]\t Toggle whether the current record is displayed in a \ +one-line\n\t listing, or a full multi-line listing. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-toggle-records-display-layout]\t Do that \ +for all displayed records. +\\[bbdb-refile-record]\t Merge the contents of the current record with \ +some other, and then\n\t delete the current record. See this command's \ +documentation. +\\[bbdb-omit-record]\t Remove the current record from the display without \ +deleting it from\n\t the database. This is often a useful thing to do \ +before using one\n\t of the `*' commands. +\\[bbdb]\t Search for records in the database (on all fields). +\\[bbdb-net]\t Search for records by net address. +\\[bbdb-company]\t Search for records by company. +\\[bbdb-notes]\t Search for records by note. +\\[bbdb-name]\t Search for records by name. +\\[bbdb-changed]\t Display records that have changed since the database \ +was saved. +\\[bbdb-send-mail]\t Compose mail to the person represented by the \ +current record. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-send-mail]\t Compose mail \ +to everyone whose record is displayed. +\\[bbdb-finger]\t Finger the net address of the current record. +\\[bbdb-ftp]\t FTP to the curent records's `ftp' field. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-finger]\t Finger the \ +net address of all displayed records. +\\[bbdb-save-db]\t Save the BBDB file to disk. +\\[bbdb-print]\t Create a TeX file containing a pretty-printed version \ +of all the\n\t records in the database. +\\[bbdb-apply-next-command-to-all-records]\\[bbdb-print]\t Do that for the \ +displayed records only. +\\[other-window]\t Move to another window. +\\[bbdb-info]\t Read the Info documentation for BBDB. +\\[bbdb-help]\t Display a one line command summary in the echo area. +\\[bbdb-www]\t Visit Web sites listed in the `www' field(s) of the current \ +record. +\\[bbdb-whois]\t run whois on the current record. + +For address completion using the names and net addresses in the database: +\t in Sendmail mode, type \\\\[bbdb-complete-name]. +\t in Message mode, type \\\\[bbdb-complete-name]. + +Variables of note: +\t bbdb-always-add-addresses +\t bbdb-auto-revert-p +\t bbdb-canonicalize-redundant-nets-p +\t bbdb-case-fold-search +\t bbdb-completion-type +\t bbdb-default-area-code +\t bbdb-default-domain +\t bbdb-electric-p +\t bbdb-display-layout +\t bbdb-file +\t bbdb-message-caching-enabled +\t bbdb-new-nets-always-primary +\t bbdb-north-american-phone-numbers-p +\t bbdb-notice-auto-save-file +\t bbdb-offer-save +\t bbdb-pop-up-display-layout +\t bbdb-pop-up-target-lines +\t bbdb-quiet-about-name-mismatches +\t bbdb-readonly-p +\t bbdb-use-alternate-names +\t bbdb-use-pop-up +\t bbdb-user-mail-names +\t bbdb/mail-auto-create-p +\t bbdb/news-auto-create-p + +There are numerous hooks. M-x apropos ^bbdb.*hook RET + +The keybindings, more precisely: +\\{bbdb-mode-map}" + (setq major-mode 'bbdb-mode) + (setq mode-name "BBDB") + (use-local-map bbdb-mode-map) + (run-hooks 'bbdb-mode-hook)) + +;;; these should be in bbdb-com.el but they're so simple, why load it all. + +(defun bbdb-next-record (p) + "Move the cursor to the first line of the next BBDB record." + (interactive "p") + (if (< p 0) + (bbdb-prev-record (- p)) + (forward-char) + (while (> p 0) + (or (re-search-forward "^[^ \t\n]" nil t) + (progn (beginning-of-line) + (error "no next record"))) + (setq p (1- p))) + (beginning-of-line))) + +(defun bbdb-prev-record (p) + "Move the cursor to the first line of the previous BBDB record." + (interactive "p") + (if (< p 0) + (bbdb-next-record (- p)) + (while (> p 0) + (or (re-search-backward "^[^ \t\n]" nil t) + (error "no previous record")) + (setq p (1- p))))) + + +(defun bbdb-maybe-update-display (bbdb-record) + (save-excursion + (save-window-excursion + (let ((w (get-buffer-window bbdb-buffer-name)) + (b (current-buffer))) + (if w + (unwind-protect + (progn (set-buffer bbdb-buffer-name) + (save-restriction + (if (assq bbdb-record bbdb-records) + (bbdb-redisplay-records)))) + (set-buffer b))))))) + +(defcustom bbdb-notes-default-separator ", " + "*The default separator inserted by `bbdb-annotate-notes'. +This is used for notes which do not have `field-separator' property set. +E.g., if you want URLs to be separated by newlines, you can put + (put 'www 'field-separator \"\\n\") +into your .emacs." + :group 'bbdb-noticing-records + :type 'string) + +(defun bbdb-annotate-notes (bbdb-record annotation &optional fieldname replace) + "Add an annotation to a record. +Adds (or replaces, when the fourth argument REPLACE is non-nil) +an ANNOTATION to the note FIELDNAME in BBDB-RECORD. +Called by `bbdb-auto-notes-hook'." + (or bbdb-record (error "unperson")) + (setq annotation (bbdb-string-trim annotation)) + (if (memq fieldname '(name address addresses phone phones net aka AKA)) + (error "bbdb: cannot annotate the %s field this way" fieldname)) + (or fieldname (setq fieldname 'notes)) + (or (memq fieldname '(notes company)) + (assoc (symbol-name fieldname) (bbdb-propnames)) + (bbdb-set-propnames (append (bbdb-propnames) + (list (list (symbol-name fieldname)))))) + (let ((notes (bbdb-string-trim + (or (bbdb-record-getprop bbdb-record fieldname) "")))) + (unless (or (string= "" annotation) + (string-match (regexp-quote annotation) notes)) + (bbdb-record-putprop bbdb-record fieldname + (if (or replace (string= notes "")) + annotation + (concat notes + (or (get fieldname 'field-separator) + bbdb-notes-default-separator) + annotation))) + (bbdb-maybe-update-display bbdb-record)))) + +(defun bbdb-offer-save () + "Offer to save the Insidious Big Brother Database if it is modified." + (if bbdb-offer-save + (bbdb-save-db (eq bbdb-offer-save t)))) + +(defcustom bbdb-save-db-timeout nil + "*If non-nil, then when `bbdb-save-db' is asking you whether to save the db, +it will time out to `yes' after this many seconds. This only works if the +function `y-or-n-p-with-timeout' is defined." + :group 'bbdb-save + :type '(choice (const :tag "Don't time out" nil) + (integer :tag "Time out after this many seconds" 5))) + +(defun bbdb-save-db (&optional prompt-first mention-if-not-saved) + "Save the DB if it is modified." + (interactive (list nil t)) + (bbdb-with-db-buffer + (if (and (buffer-modified-p) + (or (null prompt-first) + (if bbdb-readonly-p + (bbdb-y-or-n-p + "Save the BBDB, even though it's supposedly read-only? ") + (if (and bbdb-save-db-timeout + (fboundp 'y-or-n-p-with-timeout)) + (y-or-n-p-with-timeout + "Save the BBDB now? " bbdb-save-db-timeout t) + (bbdb-y-or-n-p "Save the BBDB now? "))))) + (save-buffer) + (if mention-if-not-saved (message "BBDB not saved"))))) + + +;;; mail and news interface + +(defun bbdb-clean-username (string) + "Strips garbage from the user full name string." + ;; This function is called a lot, and should be fast. But I'm loathe to + ;; remove any of the functionality in it. + (if (string-match "[@%!]" string) ; ain't no user name! It's an address! + (bbdb-string-trim string) + (let ((case-fold-search t)) + ;; Take off leading and trailing non-alpha chars \(quotes, parens, + ;; digits, etc) and things which look like phone extensions \(like + ;; "x1234" and "ext. 1234". \) + ;; This doesn't work all the time because some of our friends in + ;; northern europe have brackets in their names... + (if (string-match (if bbdb-have-re-char-classes + "\\`[^[:alpha:]]+" + "\\`[^a-z]+") + string) + (setq string (substring string (match-end 0)))) + (while (string-match + "\\(\\W+\\([Xx]\\|[Ee]xt\\.?\\)\\W*[-0-9]+\\|[^a-z]+\\)\\'" + string) + (setq string (substring string 0 (match-beginning 0)))) + ;; replace tabs, multiple spaces, dots, and underscores with a single + ;; space, but don't replace ". " with " " because that could be an + ;; initial. + (while (string-match "\\(\t\\| +\\|\\(\\.\\)[^ \t_]\\|_+\\)" string) + (setq string (concat (substring string 0 + (or (match-beginning 2) + (match-beginning 1))) + " " + (substring string (or (match-end 2) + (match-end 1)))))) + ;; If the string contains trailing parenthesized comments, nuke 'em. + (if (string-match "[^ \t]\\([ \t]*\\((\\| -\\| #\\)\\)" string) + (progn + (setq string (substring string 0 (match-beginning 1))) + ;; lose rubbish this may have exposed. + (while + (string-match + "\\(\\W+\\([Xx]\\|[Ee]xt\\.?\\)\\W*[-0-9]+\\|[^a-z]+\\)\\'" + string) + (setq string (substring string 0 (match-beginning 0)))))) + string))) + +;;; message-caching, to speed up the the mail interfaces + +(defvar bbdb-buffers-with-message-caches '() + "A list of all the buffers which have stuff on their `bbdb-message-cache' +local variable. When we re-parse the `bbdb-file', we need to flush all of +these caches.") + +(defun notice-buffer-with-cache (buffer) + (or (memq buffer bbdb-buffers-with-message-caches) + (progn + ;; First remove any deleted buffers which may have accumulated. + ;; This happens only when a buffer is added to the list, so it + ;; ought not happen that frequently (each time you read mail, say.) + (let ((rest bbdb-buffers-with-message-caches)) + (while rest + (if (null (buffer-name (car rest))) + (setq bbdb-buffers-with-message-caches + (delq (car rest) bbdb-buffers-with-message-caches))) + (setq rest (cdr rest)))) + ;; now add this buffer. + (setq bbdb-buffers-with-message-caches + (cons buffer bbdb-buffers-with-message-caches))))) + +(defvar bbdb-message-cache nil + "alist of (MESSAGE-KEY BBDB-RECORDS) cached in order to avoid updating +messages each time they are visited. This is used by all MUAs, while the +MESSAGE-KEY is specific to the MUA and the cache is local for each MUA or MUA +folder.") + +(make-variable-buffer-local 'bbdb-message-cache) + +(defun bbdb-message-cache-lookup (message-key) + "Return cached BBDB records for MESSAGE-KEY. +If not present or when the records have been modified return nil." + (bbdb-records) + (if bbdb-message-caching-enabled + (let ((records (assq message-key bbdb-message-cache)) + (invalid nil)) + (when records + (setq records (cdr records)) + (bbdb-mapc (lambda (record) + (if (bbdb-record-deleted-p record) + (setq invalid t))) + records)) + (if invalid nil records)))) + +(defun bbdb-encache-message (message-key bbdb-records) + "Cache the BBDB-RECORDS for a message identified by MESSAGE-KEY and +return them." + (and bbdb-message-caching-enabled + (car bbdb-records) + (add-to-list 'bbdb-message-cache (cons message-key bbdb-records)) + (notice-buffer-with-cache (current-buffer))) + bbdb-records) + +(defun bbdb-decache-message (message-key) + "Remove an element form the cache." + (and bbdb-message-caching-enabled + (delq (assoc message-key bbdb-message-cache) bbdb-message-cache))) + +(defun bbdb-flush-all-caches () + (bbdb-debug + (and bbdb-buffers-with-message-caches + (message "Flushing BBDB caches"))) + (save-excursion + (while bbdb-buffers-with-message-caches + (if (buffer-name (car bbdb-buffers-with-message-caches)) + (progn + (set-buffer (car bbdb-buffers-with-message-caches)) + (setq bbdb-message-cache nil))) + (setq bbdb-buffers-with-message-caches + (cdr bbdb-buffers-with-message-caches))))) + + +(defconst bbdb-name-gubbish + (concat "[-,. \t/\\]+\\(" + "[JjSs]r\\.?" + "\\|V?\\(I\\.?\\)+V?" + (concat "\\|" + (regexp-opt bbdb-lastname-prefixes)) + "\\)\\W*\\'")) + +(defun bbdb-divide-name (string) + "divide the string into a first name and a last name, cleverly." + ;; ## This shouldn't be here. + (if (string-match "\\W+\\([Xx]\\|[Ee]xt\\.?\\)\\W*[-0-9]+\\'" string) + (setq string (substring string 0 (match-beginning 0)))) + (let* ((case-fold-search nil) + (str string) + (gubbish (string-match bbdb-name-gubbish string))) + (if gubbish + (setq gubbish (substring str gubbish) + str (substring string 0 (match-beginning 0)))) + (if (string-match + (concat " +\\(" + ;; start recognize some prefixes to lastnames + (if bbdb-lastname-prefixes + (concat "\\(" + (regexp-opt bbdb-lastname-prefixes t) + "[ ]+\\)?")) + ;; end recognize some prefixes to lastnames + "\\([^ ]+ *- *\\)?[^ ]+\\)\\'") str) + (list (substring str 0 (match-beginning 0)) + (concat + (substring str (match-beginning 1)) + (or gubbish ""))) + (list string "")))) + +(defun bbdb-check-alternate-name (possible-name record) + (let (aka) + (if (setq aka (bbdb-record-aka record)) + (let ((down-name (downcase possible-name)) + match) + (while aka + (if (equal down-name (downcase (car aka))) + (setq match (car aka) + aka nil) + (setq aka (cdr aka)))) + match)))) + + +(defun bbdb-canonicalize-address (net) + ;; call the bbdb-canonicalize-net-hook repeatedly until it returns a + ;; value eq to the value passed in. This implies that it can't + ;; destructively modify the string. + + ;; Hysterical Raisins: This is a function, not a hook. In order to + ;; make this hook a hook, we'll quietly convert a single function + ;; into a hook list. We should really warn the user that we're + ;; doing this, and advise them to update their configuration + ;; accordingly. For the release, maybe. + (if (functionp bbdb-canonicalize-net-hook) + (setq bbdb-canonicalize-net-hook (list bbdb-canonicalize-net-hook))) + + ;; Now, do the hook run. Note, if you mess up, it's possible that + ;; BBDB will get stuck here oscillating between various definitions + ;; of the canonical address. + (while (not (equal net (setq net (run-hook-with-args + 'bbdb-canonicalize-net-hook net))))) + + net) + +;; Mostly written by Rod Whitby. +(defun bbdb-net-redundant-p (net old-nets) + "Returns non-nil if NET represents a sub-domain of one of the OLD-NETS. +The returned value is the address which makes this one redundant. +For example, \"foo@bar.baz.com\" is redundant w.r.t. \"foo@baz.com\", +and \"foo@quux.bar.baz.com\" is redundant w.r.t. \"foo@bar.baz.com\"." + (let ((redundant-addr nil)) + (while (and (not redundant-addr) old-nets) + ;; Calculate a host-regexp for each address in OLD-NETS + (let* ((old (car old-nets)) + (host-index (string-match "@" old)) + (name (and host-index (substring old 0 host-index))) + (host (and host-index (substring old (1+ host-index)))) + ;; host-regexp is "^@.*\.$" + (host-regexp (and name host + (concat "\\`" (regexp-quote name) + "@.*\\." (regexp-quote host) + "\\'")))) + ;; If NET matches host-regexp, then it is redundant + (if (and host-regexp net + (string-match host-regexp net)) + (setq redundant-addr old))) + (setq old-nets (cdr old-nets))) + redundant-addr)) + + +(defun bbdb-annotate-message-sender (from &optional loudly create-p + prompt-to-create-p) + "Fills the record corresponding to the sender with as much info as possible. +A record may be created by this; a record or nil is returned. +If `bbdb-readonly-p' is true, then a record will never be created. +If CREATE-P is true, then a record may be created, otherwise it won't. +If PROMPT-TO-CREATE-P is true, then the user will be asked for confirmation +before the record is created, otherwise it is created without confirmation +\(assuming that CREATE-P is true\). " + (let* ((data (if (consp from) + from ; if from is a cons, it's pre-parsed (hack hack) + (mail-extract-address-components from))) + (name (car data)) + (net (car (cdr data)))) + (if (equal name net) (setq name nil)) + (bbdb-debug + (if (equal name "") (error "mail-extr returned \"\" as name")) + (if (equal net "") (error "mail-extr returned \"\" as net"))) + + (if (and net bbdb-canonicalize-net-hook) + (setq net (bbdb-canonicalize-address net))) + + (let ((change-p nil) + (record (or (bbdb-search-simple nil net) + (bbdb-search-simple name nil))) + (created-p nil) + (fname name) + (lname nil) + old-name + bogon-mode) + (and record (setq old-name (bbdb-record-name record))) + + ;; This is to prevent having losers like "John " match + ;; against existing records like "Someone Else ". + ;; + ;; The solution implemented here is to never create or show records + ;; corresponding to a person who has a real-name which is the same + ;; as the network-address of someone in the db already. This is not + ;; a good solution. + (let (down-name old-net) + (if (and record name + (not (equal (setq down-name (downcase name)) + (and old-name (downcase old-name))))) + (progn + (setq old-net (bbdb-record-net record)) + (while old-net + (if (equal down-name (downcase (car old-net))) + (progn + (setq bogon-mode t + old-net nil) + (message + "Ignoring bogon %s's name \"%s\" to avoid name-clash with \"%s\"" + net name old-name) + (sit-for 2)) + (setq old-net (cdr old-net))))))) + + (if (or record + bbdb-readonly-p + (not create-p) + (not (or name net)) + bogon-mode) + ;; no further action required + nil + ;; otherwise, the db is writable, and we may create a record. + ;; first try to get a reasonable default name if not given + ;; often I get things like .@ ... + (if (or (null name) (and (stringp name) (string= "" name))) + (if (string-match "^[^@]+" net) + (setq name (bbdb-clean-username (match-string 0 net))))) + (setq record (if (or (null prompt-to-create-p) + create-p + (if (functionp prompt-to-create-p) + (bbdb-invoke-hook-for-value + prompt-to-create-p) + (bbdb-y-or-n-p + (format "%s is not in the db. Add? " + (or name net))))) + (make-vector bbdb-record-length nil)) + created-p (not (null record))) + (if record + (bbdb-record-set-cache record (make-vector bbdb-cache-length nil))) + ) + (if (or bogon-mode (null record)) + nil + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "nasty nasty deleted record nasty."))) + (if (and name + (not (equal (and name (downcase name)) + (and old-name (downcase old-name)))) + (or (null bbdb-use-alternate-names) + (not (bbdb-check-alternate-name name record))) + (let ((fullname (bbdb-divide-name name)) + tmp) + (setq fname (car fullname) + lname (nth 1 fullname)) + (not (and (equal (downcase fname) + (and (setq tmp + (bbdb-record-firstname record)) + (downcase tmp))) + (equal (downcase lname) + (and (setq tmp + (bbdb-record-lastname record)) + (downcase tmp))))))) + + ;; have a message-name, not the same as old name. + (cond (bbdb-readonly-p nil);; skip if readonly + + ;; ignore name mismatches? + ;; NB 'quiet' means 'don't ask', not 'don't mention' + ((and bbdb-quiet-about-name-mismatches old-name) + (let ((sit-for-secs + (if (numberp bbdb-quiet-about-name-mismatches) + bbdb-quiet-about-name-mismatches + 2))) + (if (or bbdb-silent-running (= 0 sit-for-secs)) nil + (message "name mismatch: \"%s\" changed to \"%s\"" + (bbdb-record-name record) name) + (sit-for sit-for-secs)))) + ((or created-p + (if bbdb-silent-running t + (if (null old-name) + (bbdb-y-or-n-p + (format "Assign name \"%s\" to address \"%s\"? " + name (car (bbdb-record-net record)))) + (bbdb-y-or-n-p + (format "Change name \"%s\" to \"%s\"? " + old-name name))))) + (setq change-p 'sort) + + ;; Keep old name? + (and old-name bbdb-use-alternate-names + (not (member old-name (bbdb-record-aka record))) + ;; Silent mode: just add it. + (if bbdb-silent-running + (bbdb-record-set-aka record + (cons old-name + (bbdb-record-aka + record))) + ;; prompt user otherwise. + (if (bbdb-y-or-n-p + (format "Keep name \"%s\" as an AKA? " + old-name)) + (bbdb-record-set-aka record + (cons old-name + (bbdb-record-aka + record))) + (bbdb-remhash (downcase old-name) record)))) + + (bbdb-record-set-namecache record nil) + (bbdb-record-set-firstname record fname) + (bbdb-record-set-lastname record lname) + (bbdb-debug (or fname lname + (error "bbdb: should have a name by now"))) + (bbdb-puthash (downcase (bbdb-record-name record)) record)) + + ;; not quiet about mismatches + ((and old-name bbdb-use-alternate-names + ;; dedupe + (not (member old-name (bbdb-record-aka record))) + (if (not bbdb-silent-running) + (bbdb-y-or-n-p + (format "Make \"%s\" an alternate for \"%s\"? " + name old-name)))) + (setq change-p 'sort) + (bbdb-record-set-aka + record (cons name (bbdb-record-aka record))) + (bbdb-puthash (downcase name) record)))) + + ;; It's kind of a kludge that the "redundancy" concept is built in. + ;; Maybe I should just add a new hook here... The problem is that the + ;; canonicalize-net-hook is run before database lookup, and thus can't + ;; refer to the database to determine whether a net is redundant. + (if bbdb-canonicalize-redundant-nets-p + (setq net (or (bbdb-net-redundant-p net (bbdb-record-net record)) + net))) + + (if (and net (not bbdb-readonly-p)) + (if (null (bbdb-record-net record)) + ;; names are always a sure match, so don't bother prompting + ;; here. + (progn (bbdb-record-set-net record (list net)) + (bbdb-puthash (downcase net) record) ; important! + (or change-p (setq change-p t))) + ;; new address; ask before adding. + (if (let ((rest-net (bbdb-record-net record)) + (new (downcase net)) + (match nil)) + (while (and rest-net (null match)) + (setq match (string= new (downcase (car rest-net))) + rest-net (cdr rest-net))) + match) + nil + (if (let ((bbdb-always-add-addresses + bbdb-always-add-addresses)) + (if (functionp bbdb-always-add-addresses) + (setq bbdb-always-add-addresses + (funcall bbdb-always-add-addresses))) + (cond + ;; add it automatically + ((eq bbdb-always-add-addresses t) + t) + ;; do not add it + ((null bbdb-always-add-addresses) + nil) + ;; ask the user if it should be added + (t + (and + (not (equal net "???")) + (let ((the-first-bit + (format "Add address \"%s\" to \"" net)) + ;; this groveling is to prevent the "(y or n)" + ;; from falling off the right edge of the + ;; screen. + (the-next-bit (mapconcat 'identity + (bbdb-record-net + record) + ", ")) + (w (window-width (minibuffer-window)))) + (if (> (+ (length the-first-bit) + (length the-next-bit) 15) w) + (setq the-next-bit + (concat + (substring + the-next-bit + 0 (max 0 (- w (length the-first-bit) + 20))) + "..."))) + (bbdb-display-records (list record)) + (if (bbdb-y-or-n-p (concat the-first-bit + the-next-bit + "\"? ")) + ;; then add the new net + t + ;; else add a new record with the same name + (if (and create-p + (or (null prompt-to-create-p) + (if (functionp prompt-to-create-p) + (bbdb-invoke-hook-for-value + prompt-to-create-p) + (bbdb-y-or-n-p + (format + "Create a new record for %s? " + (bbdb-record-name record)))))) + (setq record + (bbdb-create-internal name nil net + nil nil nil))) + nil)))))) + ;; then modify an existing record + (let ((front-p (cond ((null bbdb-new-nets-always-primary) + (bbdb-y-or-n-p + (format + "Make \"%s\" the primary address? " + net))) + ((eq bbdb-new-nets-always-primary t) + t) + (t nil)))) + (bbdb-record-set-net record + (if front-p + (cons net (bbdb-record-net + record)) + (nconc (bbdb-record-net record) + (list net)))) + (bbdb-puthash (downcase net) record) ; important! + (or change-p (setq change-p t))))))) + + (bbdb-debug + (if (and change-p bbdb-readonly-p) + (error + "doubleplus ungood: how did we change anything in readonly mode?" + ))) + (if (and loudly change-p (not bbdb-silent-running)) + (if (eq change-p 'sort) + (message "noticed \"%s\"" (bbdb-record-name record)) + (if (bbdb-record-name record) + (message "noticed %s's address \"%s\"" + (bbdb-record-name record) net) + (message "noticed naked address \"%s\"" net)))) + + (if created-p + (bbdb-invoke-hook 'bbdb-create-hook record)) + + (if change-p + (bbdb-change-record record (eq change-p 'sort))) + + ;; only invoke bbdb-notice-hook if we actually noticed something + (if record + (let ((inside-bbdb-notice-hook t)) + (bbdb-invoke-hook 'bbdb-notice-hook record))) + + record)))) + + +;;; window configuration hackery +;;;###autoload +(defcustom bbdb-multiple-buffers nil + "When non-nil we create a new buffer of every buffer causing pop-ups. +You can also set this to a function returning a buffer name." + :group 'bbdb-record-display + :type '(choice (const :tag "Disabled" nil) + (function :tag "Enabled" bbdb-multiple-buffers-default) + (function :tag "User defined function"))) + +(defun bbdb-multiple-buffers-default () + "Default function for guessing a better name for new *BBDB* buffers." + (cond ((memq major-mode '(vm-mode vm-summary-mode + vm-presentation-mode + vm-virtual-mode)) + (vm-select-folder-buffer) + (buffer-name)) + ((memq major-mode '(gnus-summary-mode gnus-group-mode)) + (set-buffer gnus-article-buffer) + (buffer-name)) + ((memq major-mode '(mail-mode vm-mail-mode message-mode)) + "message composition"))) + +(defun bbdb-multiple-buffers-set-name (&optional buffer-list new-name) + (setq new-name (or new-name + (concat " *BBDB " (funcall bbdb-multiple-buffers) "*")) + buffer-list (append (list (current-buffer) + (get-buffer-create new-name)) + buffer-list)) + + (save-excursion + (while buffer-list + (set-buffer (car buffer-list)) + (make-local-variable 'bbdb-buffer-name) + (setq bbdb-buffer-name new-name) + (setq buffer-list (cdr buffer-list))))) + +(defun bbdb-pop-up-bbdb-buffer (&optional horiz-predicate) + "Find the largest window on the screen, and split it, displaying the +*BBDB* buffer in the bottom 'bbdb-pop-up-target-lines' lines (unless +the *BBDB* buffer is already visible, in which case do nothing.) + +If 'bbdb-use-pop-up' is the symbol 'horiz, and the first window +matching HORIZ-PREDICATE is sufficiently wide (> 100 columns) then +the window will be split vertically rather than horizontally. + +If `bbdb-multiple-buffers' is set we create a new BBDB buffer when not +already within one. The new buffer-name starts with a space, i.e. it does +not clutter the buffer-list." + + (let ((b (current-buffer)) + new-bbdb-buffer-name) + + ;; create new BBDB buffer if multiple buffers are desired. + (when (and bbdb-multiple-buffers (not (eq major-mode 'bbdb-mode))) + (bbdb-multiple-buffers-set-name (list b))) + (setq new-bbdb-buffer-name bbdb-buffer-name) + + ;; now get the pop-up + (if (get-buffer-window new-bbdb-buffer-name) + nil + (if (and (eq bbdb-use-pop-up 'horiz) + horiz-predicate + (bbdb-pop-up-bbdb-buffer-horizontally horiz-predicate)) + nil + (let* ((first-window (selected-window)) + (tallest-window first-window) + (window first-window)) + ;; find the tallest window... + (while (not (eq (setq window (previous-window window)) first-window)) + (if (> (window-height window) (window-height tallest-window)) + (setq tallest-window window))) + ;; select it and split it... + (select-window tallest-window) + (let ((size (min + (- (window-height tallest-window) + window-min-height 1) + (- (window-height tallest-window) + (max window-min-height + (1+ bbdb-pop-up-target-lines)))))) + (split-window tallest-window + (if (> size 0) size window-min-height))) + (if (memq major-mode + '(gnus-Group-mode gnus-Subject-mode gnus-Article-mode)) + (goto-char (point-min))) ; make gnus happy... + ;; goto the bottom of the two... + (select-window (next-window)) + ;; make it display *BBDB*... + (let ((pop-up-windows nil)) + (switch-to-buffer (get-buffer-create new-bbdb-buffer-name))) + ;; select the original window we were in... + (select-window first-window))) + ;; and make sure the current buffer is correct as well. + (set-buffer b) + nil))) + +(defun bbdb-pop-up-bbdb-buffer-horizontally (predicate) + (if (<= (frame-width) 112) + nil + (let* ((first-window (selected-window)) + (got-it nil) + (window first-window)) + (while (and (not (setq got-it (funcall predicate window))) + (not (eq first-window (setq window (next-window window))))) + ) + (if (or (null got-it) + (<= (window-width window) 112)) + nil + (let ((b (current-buffer))) + (select-window window) + (split-window-horizontally 80) + (select-window (next-window window)) + (let ((pop-up-windows nil)) + (switch-to-buffer (get-buffer-create bbdb-buffer-name))) + (select-window first-window) + (set-buffer b) + t))))) + +(defun bbdb-version (&optional arg) + "Return string describing the version of the BBDB that is running. +When called interactively with a prefix argument, insert string at point." + (interactive "P") + (let ((version-string (format "BBDB version %s (%s)" + bbdb-version bbdb-version-date))) + (cond + (arg + (insert (message version-string))) + ((interactive-p) + (message version-string)) + (t version-string)))) + + ;;; resorting, which really shouldn't be necesary... + +(defun bbdb-record-lessp-fn (record1 record2) ; for use as a funarg + (bbdb-record-lessp record1 record2)) + +(defun bbdb-resort-database () + "*Resort BBDB database as a last resort. +This is not be needed when using BBDB itself. It might be necessary +after having used inferior software to add entries to the BBDB, however." + (interactive) + (let* ((records (copy-sequence (bbdb-records)))) + (bbdb-with-db-buffer + (setq bbdb-records (sort bbdb-records 'bbdb-record-lessp-fn)) + (if (equal records bbdb-records) + nil + (message "DANGER! BBDB was mis-sorted; it's being fixed...") + (goto-char (point-min)) + (cond ((eq (following-char) ?\[) nil) + ((search-forward "\n[" nil 0) (forward-char -1))) + (delete-region (point) bbdb-end-marker) + (let ((print-escape-newlines t) + (standard-output (current-buffer)) + (inhibit-quit t) ; really, don't fuck with this + record cache) + (setq records bbdb-records) + (while records + (setq record (car records) + cache (bbdb-record-cache record)) + (bbdb-record-set-cache record nil) + (prin1 (car records)) + (bbdb-record-set-cache record cache) + (insert ?\n) + (setq records (cdr records)))) + (kill-all-local-variables) + (error "the BBDB was mis-sorted: it has been repaired."))))) + +(defvar bbdb-init-forms + '((gnus ; gnus 3.15 or newer + (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)) + (mh-e ; MH-E + (add-hook 'mh-folder-mode-hook 'bbdb-insinuate-mh)) + (rmail ; RMAIL + (add-hook 'rmail-mode-hook 'bbdb-insinuate-rmail)) + (sendmail ; the standard mail user agent + (add-hook 'mail-setup-hook 'bbdb-insinuate-sendmail)) + (vm-old ; the alternative mail reader + (add-hook 'vm-load-hook 'bbdb-insinuate-vm)) + (vm ; newer versions don't have vm-load-hook + (progn (eval-after-load "vm" '(bbdb-insinuate-vm)))) + (message ; the gnus mail user agent + (add-hook 'message-setup-hook 'bbdb-insinuate-message)) + (reportmail ; mail notification + (add-hook 'reportmail-load-hook 'bbdb-insinuate-reportmail)) + (sc ; message citation + (add-hook 'sc-load-hook 'bbdb-insinuate-sc)) + (supercite ; same + (add-hook 'sc-load-hook 'bbdb-insinuate-sc)) + (w3 ; WWW browser + (add-hook 'w3-load-hook 'bbdb-insinuate-w3))) + "The alist which maps features to insinuation forms.") + +;;;###autoload +(defun bbdb-initialize (&rest to-insinuate) +"*Initialize the BBDB. One or more of the following symbols can be +passed as arguments to initiate the appropriate insinuations. + + Initialization of mail/news readers: + + gnus Initialize BBDB support for the gnus mail/news reader + version 3.15 or newer. If you pass the `gnus' symbol, + you should probably also pass the `message' symbol. + mh-e Initialize BBDB support for the MH-E mail reader. + rmail Initialize BBDB support for the RMAIL mail reader. + sendmail Initialize BBDB support for sendmail (M-x mail). + vm Initialize BBDB support for the VM mail reader. + NOTE: For the VM insinuation to work properly, you must + either call `bbdb-initialize' with the `vm' symbol from + within your VM initialization file (\"~/.vm\") or you + must call `bbdb-insinuate-vm' manually from within your + VM initialization file. + + Initialization of miscellaneous package: + + message Initialize BBDB support for Message mode. + reportmail Initialize BBDB support for the Reportmail mail + notification package. + sc or Initialize BBDB support for the Supercite message + supercite citation package. + w3 Initialize BBDB support for Web browsers." + + (defalias 'advertized-bbdb-delete-current-field-or-record + 'bbdb-delete-current-field-or-record) + + (require 'bbdb-autoloads) + + (while to-insinuate + (let* ((feature (car to-insinuate)) + (init (assq feature bbdb-init-forms))) + (setq to-insinuate (cdr to-insinuate)) + (if init + (if (or (featurep feature) (locate-library (symbol-name feature))) + (eval (cadr init)) + (bbdb-warn "cannot locate feature `%s'" feature)) + (bbdb-warn "don't know how to insinuate `%s'" feature)))) + + ;; RMAIL, MHE, and VM interfaces might need these. + (autoload 'mail-strip-quoted-names "mail-utils") + (autoload 'mail-fetch-field "mail-utils") + ;; All of the interfaces need this. + (autoload 'mail-extract-address-components "mail-extr") + + (run-hooks 'bbdb-initialize-hook)) + +;; Initialize keymaps +(unless bbdb-mode-search-map + (define-prefix-command 'bbdb-mode-search-map) + (if (fboundp 'set-keymap-prompt) + (set-keymap-prompt + bbdb-mode-search-map + "(Search [n]ame, [c]ompany, net [a]ddress, n[o]tes)?")) + + (define-key bbdb-mode-search-map [(n)] 'bbdb-name) + (define-key bbdb-mode-search-map [(c)] 'bbdb-company) + (define-key bbdb-mode-search-map [(a)] 'bbdb-net) + (define-key bbdb-mode-search-map [(o)] 'bbdb-notes)) + +(unless bbdb-mode-map + (setq bbdb-mode-map (make-keymap)) + (suppress-keymap bbdb-mode-map) + + (define-key bbdb-mode-map [(S)] 'bbdb-mode-search-map) + + (define-key bbdb-mode-map [(*)] 'bbdb-apply-next-command-to-all-records) + (define-key bbdb-mode-map [(+)] 'bbdb-append-records) + (define-key bbdb-mode-map [(!)] 'bbdb-search-invert-set) + (define-key bbdb-mode-map [(a)] 'bbdb-add-or-remove-mail-alias) + (define-key bbdb-mode-map [(e)] 'bbdb-edit-current-field) + (define-key bbdb-mode-map [(n)] 'bbdb-next-record) + (define-key bbdb-mode-map [(p)] 'bbdb-prev-record) + (define-key bbdb-mode-map [(d)] 'bbdb-delete-current-field-or-record) + (define-key bbdb-mode-map [(control k)] 'bbdb-delete-current-field-or-record) + (define-key bbdb-mode-map [(control o)] 'bbdb-insert-new-field) + (define-key bbdb-mode-map [(s)] 'bbdb-save-db) + (define-key bbdb-mode-map [(control x) (control s)] + 'bbdb-save-db) + (define-key bbdb-mode-map [(r)] 'bbdb-refile-record) + (define-key bbdb-mode-map [(t)] 'bbdb-toggle-records-display-layout) + (define-key bbdb-mode-map [(T)] 'bbdb-display-record-completely) + (define-key bbdb-mode-map [(o)] 'bbdb-omit-record) + (define-key bbdb-mode-map [(?\;)] 'bbdb-record-edit-notes) + (define-key bbdb-mode-map [(m)] 'bbdb-send-mail) + (define-key bbdb-mode-map "\M-d" 'bbdb-dial) + (define-key bbdb-mode-map [(f)] 'bbdb-finger) + (define-key bbdb-mode-map [(F)] 'bbdb-ftp) + (define-key bbdb-mode-map [(i)] 'bbdb-info) + (define-key bbdb-mode-map [(??)] 'bbdb-help) + (define-key bbdb-mode-map [(q)] 'bbdb-bury-buffer) + (define-key bbdb-mode-map [(control x) (control t)] + 'bbdb-transpose-fields) + (define-key bbdb-mode-map [(w)] 'bbdb-www) + (define-key bbdb-mode-map [(W)] 'bbdb-whois) + (define-key bbdb-mode-map [(P)] 'bbdb-print) + (define-key bbdb-mode-map [(h)] 'other-window) + (define-key bbdb-mode-map [(=)] 'delete-other-windows) + (define-key bbdb-mode-map [(c)] 'bbdb-create) + (define-key bbdb-mode-map [(C)] 'bbdb-changed) + (define-key bbdb-mode-map [(b)] 'bbdb) + + (define-key bbdb-mode-map [delete] 'scroll-down) + (define-key bbdb-mode-map " " 'scroll-up) + ) + + +;;; Support for the various Emacsen. This is for features that the +;;; BBDB adds to itself for different Emacsen. For definitions of +;;; functions that aren't present in various Emacsen (for example, +;;; cadr for Emacs 19.34), see below +(when (string-match "XEmacs\\|Lucid" emacs-version) + ;; Above + (fset 'bbdb-warn 'warn) + + ;; bbdb-com.el + (fset 'bbdb-display-completion-list 'bbdb-xemacs-display-completion-list)) + +(defun bbdb-insinuate-sendmail () + "Call this function to hook BBDB into sendmail (that is, M-x mail)." + (define-key mail-mode-map "\M-\t" 'bbdb-complete-name)) + +;;;###autoload +(defun bbdb-insinuate-message () + "Call this function to hook BBDB into `message-mode'." + (define-key message-mode-map "\M-\t" 'bbdb-complete-name)) + +;;; Erm. says here that (require...) can take a noerror flag; why do +;;; we have this function? +(defmacro safe-require (thing) + (list 'condition-case nil (list 'require thing) '(file-error nil))) + +;; Wrappers for things that change for different Emacsen. Note: This +;; is for things that get redefined that don't belong elsewhere. Some +;; functions that get redefined live elsewhere in the source because +;; it makes sense to put them there. + +(defun bbdb-warn (&rest args) + (beep 1) + (apply 'message args)) + + +(provide 'bbdb) ; provide before loading things which might require + +(run-hooks 'bbdb-load-hook) diff --git a/xemacs-packages/lisp/bbdb/bbdb.elc b/xemacs-packages/lisp/bbdb/bbdb.elc new file mode 100644 index 0000000000000000000000000000000000000000..5e370f2af37afab5f03187ff746566c11cb6a027 GIT binary patch literal 96928 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 C?>K4z literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/ChangeLog b/xemacs-packages/lisp/c-support/ChangeLog new file mode 100644 index 00000000..33136b26 --- /dev/null +++ b/xemacs-packages/lisp/c-support/ChangeLog @@ -0,0 +1,97 @@ +2005-07-27 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.22 released. + +2005-04-19 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.21 released. + +2005-04-15 Adrian Aichner + + * cmacexp.el (c-macro-expansion): Use shell-command-switch. + +2004-02-11 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.20 released. + +2004-02-02 Jerry James + + * hideshow.el: Sync with Emacs 21.3. + +2004-01-05 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.19 released. + +2003-12-02 Nix + + * hideshow.el (hs-grok-mode-type): Don't fail if comment-start or + comment-end are nil. + +2003-10-31 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.18 released. + +2003-09-15 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.17 released. + +2003-03-09 Ben Wing + + * Makefile: + Delete explicit compile:: and binkit: rules. + Don't add custom-load.elc to the list of generated elc's. + +2002-11-29 Ben Wing + + * .cvsignore: Remove files now handled automatically by CVS. + * Makefile: Use `compile' instead of hard-coded `all'. + +2002-10-15 Ville Skyttä + + * Makefile (srckit): Remove. + +2000-10-05 Martin Buchholz + + * *: Mega typo fix. + +1999-09-09 Jeff Miller + + * hideif.el: sync with Emacs 20.4. + +1999-03-02 SL Baur + + * hideif.el (hide-ifdef-mode-map): Autoload. + +1999-02-06 Jan Vroonhof + + * hideif.el (hide-ifdef-mode): Don't quote keymap when passing to + add-minor-mode. + +1998-03-25 SL Baur + + * ctypes.el: new file. + +1998-03-21 SL Baur + + * c-comment-edit.el-1.02 from Kyle Jones + +1998-02-26 SL Baur + + * c-comment-edit.el-1.01 from Kyle Jones. + +1998-01-24 SL Baur + + * Makefile (VERSION): Update to package standard 1.0. + * package-info.in: Ditto. + +1998-01-12 SL Baur + + * Makefile: Update to newer package interface. + +1998-01-03 SL Baur + + * Makefile: Update to newer package interface. + +1997-12-29 SL Baur + + * Makefile: Created. diff --git a/xemacs-packages/lisp/c-support/_pkg.el b/xemacs-packages/lisp/c-support/_pkg.el new file mode 100644 index 00000000..ac0b99ad --- /dev/null +++ b/xemacs-packages/lisp/c-support/_pkg.el @@ -0,0 +1,5 @@ +;;;###autoload +(package-provide 'c-support + :version 1.22 + :author-version "No-Upstream-Ver" + :type 'single-file) diff --git a/xemacs-packages/lisp/c-support/auto-autoloads.el b/xemacs-packages/lisp/c-support/auto-autoloads.el new file mode 100644 index 00000000..a847b188 --- /dev/null +++ b/xemacs-packages/lisp/c-support/auto-autoloads.el @@ -0,0 +1,252 @@ +;;; DO NOT MODIFY THIS FILE +(if (featurep 'c-support-autoloads) (error "Already loaded")) + +;;;### (autoloads nil "_pkg" "c-support/_pkg.el") + +(package-provide 'c-support :version 1.22 :author-version "No-Upstream-Ver" :type 'single-file) + +;;;*** + +;;;### (autoloads (c-comment-edit) "c-comment-edit" "c-support/c-comment-edit.el") + +(autoload 'c-comment-edit "c-comment-edit" "\ +Edit multi-line C comments. +This command allows the easy editing of a multi-line C comment like this: + /* + * ... + * ... + */ +The comment may be indented or flush with the left margin. + +If point is within a comment, that comment is used. Otherwise the +comment to be edited is found by searching forward from point. + +With one \\[universal-argument] searching starts after moving back one + paragraph. +With two \\[universal-argument]'s searching starts at the beginning of the + current or proceeding C function. +With three \\[universal-argument]'s searching starts at the beginning of the + current page. +With four \\[universal-argument]'s searching starts at the beginning of the + current buffer (clipping restrictions apply). + +Once located, the comment is copied into a temporary buffer, the comment +leaders and delimiters are stripped away and the resulting buffer is +selected for editing. The major mode of this buffer is controlled by +the variable `c-comment-edit-mode'.\\ + +Use \\[c-comment-edit-end] when you have finished editing the comment. The +comment will be inserted into the original buffer with the appropriate +delimiters and indention, replacing the old version of the comment. If +you don't want your edited version of the comment to replace the +original, use \\[c-comment-edit-abort]." t nil) + +;;;*** + +;;;### (autoloads (c-macro-expand) "cmacexp" "c-support/cmacexp.el") + +(autoload 'c-macro-expand "cmacexp" "\ +Expand C macros in the region, using the C preprocessor. +Normally display output in temp buffer, but +prefix arg means replace the region with it. + +`c-macro-preprocessor' specifies the preprocessor to use. +Prompt for arguments to the preprocessor (e.g. `-DDEBUG -I ./include') +if the user option `c-macro-prompt-flag' is non-nil. + +Noninteractive args are START, END, SUBST. +For use inside Lisp programs, see also `c-macro-expansion'." t nil) + +;;;*** + +;;;### (autoloads (ctypes-read-file ctypes-auto-parse-mode ctypes-file ctypes-dir ctypes-tags ctypes-all-buffers ctypes-buffer ctypes-define-type-in-mode ctypes-define-type) "ctypes" "c-support/ctypes.el") + +(autoload 'ctypes-define-type "ctypes" "\ +Add a new TYPE to current major mode and inform font-lock. + +When preceded by C-u the display is not updated. + +Return non-nil if the type was not known before." t nil) + +(autoload 'ctypes-define-type-in-mode "ctypes" "\ +Add TYPE to major mode MODE and inform font-lock. + +When preceded by C-u the display is not updated. + +\(This function is designed for interactive use, please call +`ctypes-define-type' from Lisp programs.)" t nil) + +(autoload 'ctypes-buffer "ctypes" "\ +Search for types in buffer, inform font-lock if any is found. + +When preceded by C-u the action is not performed. + +Return non-nil if new types are found." t nil) + +(autoload 'ctypes-all-buffers "ctypes" "\ +Search for types in all buffers, inform font-lock about all discoveries. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." t nil) + +(autoload 'ctypes-tags "ctypes" "\ +Search for types in files in the visited TAGS table. +Should no tags table be visited, the user will be prompted for a new. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." t nil) + +(autoload 'ctypes-dir "ctypes" "\ +Search for types in files in a directory hierarchy. + +See variable `ctypes-dir-read-file' for a description of which files +are opened during scanning, and how you can change the behavior. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." t nil) + +(autoload 'ctypes-file "ctypes" "\ +Search for types in file FILE. +Should FILE not be loaded it is read into a temporary buffer. + +Return mode of file, if new types was found." t nil) + +(autoload 'ctypes-auto-parse-mode "ctypes" "\ +Toggle CTypes auto parse mode; search all new buffers for types. +With arg, turn types Auto Mode on if and only if arg is positive. + +This a global minor mode, it does not have a private keymap, nor does +it add itself to the mode line. + +Place the following in your startup file to enable this feature in +future sessions: + + (require 'ctypes) + (ctypes-auto-parse-mode 1) + +When activated, the functions in the hook `ctypes-auto-parse-mode-hook' +is called with no args." t nil) + +(autoload 'ctypes-read-file "ctypes" "\ +Load types previously saved with `ctypes-write-file'. +The name of the file is given by the optional argument FILE. +Should no file name be given the value of the variable `ctypes-file-name' +is used. + +Please note that the types read will be added to the current types. + +When preceded by C-u the display is not updated. + +The third argument, NO-ERROR, determines whether or not we should +raise an error if there should be any problem loading the file. + +Should the fourth argument, QUIETLY, be non-nil no messages are +generated when the file is loaded. + +Return non-nil if new types are found." t nil) + +;;;*** + +;;;### (autoloads (hide-ifdef-mode) "hideif" "c-support/hideif.el") + +(defvar hide-ifdef-mode-map nil "\ +Keymap used with Hide-Ifdef mode.") + +(add-minor-mode 'hide-ifdef-mode " Ifdef" hide-ifdef-mode-map) + +(autoload 'hide-ifdef-mode "hideif" "\ +Toggle Hide-Ifdef mode. This is a minor mode, albeit a large one. +With ARG, turn Hide-Ifdef mode on if arg is positive, off otherwise. +In Hide-Ifdef mode, code within #ifdef constructs that the C preprocessor +would eliminate may be hidden from view. Several variables affect +how the hiding is done: + +hide-ifdef-env + An association list of defined and undefined symbols for the + current buffer. Initially, the global value of `hide-ifdef-env' + is used. + +hide-ifdef-define-alist + An association list of defined symbol lists. + Use `hide-ifdef-set-define-alist' to save the current `hide-ifdef-env' + and `hide-ifdef-use-define-alist' to set the current `hide-ifdef-env' + from one of the lists in `hide-ifdef-define-alist'. + +hide-ifdef-lines + Set to non-nil to not show #if, #ifdef, #ifndef, #else, and + #endif lines when hiding. + +hide-ifdef-initially + Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode + is activated. + +hide-ifdef-read-only + Set to non-nil if you want to make buffers read only while hiding. + After `show-ifdefs', read-only status is restored to previous value. + +\\{hide-ifdef-mode-map}" t nil) + +(defcustom hide-ifdef-initially nil "*Non-nil means call `hide-ifdefs' when Hide-Ifdef mode is first activated." :type 'boolean :group 'hide-ifdef) + +(defcustom hide-ifdef-read-only nil "*Set to non-nil if you want buffer to be read-only while hiding text." :type 'boolean :group 'hide-ifdef) + +(defcustom hide-ifdef-lines nil "*Non-nil means hide the #ifX, #else, and #endif lines." :type 'boolean :group 'hide-ifdef) + +;;;*** + +;;;### (autoloads (hs-minor-mode) "hideshow" "c-support/hideshow.el") + +(defcustom hs-hide-comments-when-hiding-all t "*Hide the comments too when you do an `hs-hide-all'." :type 'boolean :group 'hideshow) + +(defvar hs-special-modes-alist '((c-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning) (c++-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning) (bibtex-mode ("^@\\S(*\\(\\s(\\)" 1)) (java-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning)) "\ +*Alist for initializing the hideshow variables for different modes. +Each element has the form + (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC). + +If non-nil, hideshow will use these values as regexps to define blocks +and comments, respectively for major mode MODE. + +START, END and COMMENT-START are regular expressions. A block is +defined as text surrounded by START and END. + +As a special case, START may be a list of the form (COMPLEX-START +MDATA-SELECTOR), where COMPLEX-START is a regexp w/ multiple parts and +MDATA-SELECTOR an integer that specifies which sub-match is the proper +place to adjust point, before calling `hs-forward-sexp-func'. For +example, see the `hs-special-modes-alist' entry for `bibtex-mode'. + +For some major modes, `forward-sexp' does not work properly. In those +cases, FORWARD-SEXP-FUNC specifies another function to use instead. + +See the documentation for `hs-adjust-block-beginning' to see what is the +use of ADJUST-BEG-FUNC. + +If any of the elements is left nil or omitted, hideshow tries to guess +appropriate values. The regexps should not contain leading or trailing +whitespace. Case does not matter.") + +(autoload 'hs-minor-mode "hideshow" "\ +Toggle hideshow minor mode. +With ARG, turn hideshow minor mode on if ARG is positive, off otherwise. +When hideshow minor mode is on, the menu bar is augmented with hideshow +commands and the hideshow commands are enabled. +The value '(hs . t) is added to `buffer-invisibility-spec'. + +The main commands are: `hs-hide-all', `hs-show-all', `hs-hide-block', +`hs-show-block', `hs-hide-level' and `hs-toggle-hiding'. There is also +`hs-hide-initial-comment-block' and `hs-mouse-toggle-hiding'. + +Turning hideshow minor mode off reverts the menu bar and the +variables to default values and disables the hideshow commands. + +Lastly, the normal hook `hs-minor-mode-hook' is run using `run-hooks'. + +Key bindings: +\\{hs-minor-mode-map}" t nil) + +;;;*** + +(provide 'c-support-autoloads) diff --git a/xemacs-packages/lisp/c-support/auto-autoloads.elc b/xemacs-packages/lisp/c-support/auto-autoloads.elc new file mode 100644 index 0000000000000000000000000000000000000000..e96f583d9f245a17b22fffcd192e3485676b273e GIT binary patch literal 9852 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/c-comment-edit.el b/xemacs-packages/lisp/c-support/c-comment-edit.el new file mode 100644 index 00000000..ef46af91 --- /dev/null +++ b/xemacs-packages/lisp/c-support/c-comment-edit.el @@ -0,0 +1,323 @@ +;; c-comment-edit.el --- edit C comments +;; Copyright (C) 1987, 1988, 1989, 1998 Kyle E. Jones + +;; Author: Kyle Jones +;; Maintainer: Kyle Jones +;; Keywords: languages + +;; This program 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 1, or (at your option) +;; any later version. +;; +;; This program 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. +;; +;; A copy of the GNU General Public License can be obtained from this +;; program's author (send electronic mail to kyle_jones@wonderworks.com) +;; or from the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, +;; MA 02139, USA. + +;;; Synched up with: Not in FSF. + +;;; Commentary: + +;; Send bug reports to kyle_jones@wonderworks.com + +;; The command c-comment-edit is the entry point for this library. + +(provide 'c-comment-edit) + +(defvar c-comment-edit-version "1.02" + "Version number for the C Comment Edit package.") + +(defvar c-comment-edit-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\e" 'c-comment-edit-end) + (define-key map "\C-c\C-c" 'c-comment-edit-end) + (define-key map "\C-c\C-]" 'c-comment-edit-abort) + map ) + "Keymap for c-comment-edit buffers") + +(defvar c-comment-leader " *" + "*Leader used when rebuilding edited C comments. The value of this variable +should be a two-character string. Values of \" \", \" *\" and \"**\" produce +the comment styles: + /* /* /* + ... * ... ** ... + ... * ... ** ... + */ */ */ +respectively.") + +(defconst c-comment-leader-regexp "^[ ]*\\(\\*\\*\\|\\*\\)?[ ]?" + "Regexp used to match C comment leaders.") + +(defvar c-comment-edit-mode 'text-mode + "*Major mode used by `c-comment-edit' when editing C comments.") + +(defvar c-comment-edit-hook nil + "*Function to call whenever `c-comment-edit' is used. +The function is called just before the `c-comment-edit' function allows you to +begin editing the comment.") + +(defvar c-comment-edit-buffer-alist nil + "Assoc list of C buffers and their associated comment buffers. +Elements are of the form (C-BUFFER COMMENT-BUFFER COMMENT-START COMMENT-END) +COMMENT-START and COMMENT-END are markers in the C-BUFFER.") + +(defmacro save-point (&rest body) + "Save value of point, evaluates FORMS and restore value of point. +If the saved value of point is no longer valid go to (point-max). +The variable `save-point' is lambda-bound to the value of point for +the duration of this call." + (list 'let '((save-point (point))) + (list 'unwind-protect + (cons 'progn body) + '(goto-char (min (point-max) save-point))))) + +(defmacro marker (pos &optional buffer) + (list 'set-marker '(make-marker) pos buffer)) + +;;;###autoload +(defun c-comment-edit (search-prefix) + "Edit multi-line C comments. +This command allows the easy editing of a multi-line C comment like this: + /* + * ... + * ... + */ +The comment may be indented or flush with the left margin. + +If point is within a comment, that comment is used. Otherwise the +comment to be edited is found by searching forward from point. + +With one \\[universal-argument] searching starts after moving back one + paragraph. +With two \\[universal-argument]'s searching starts at the beginning of the + current or proceeding C function. +With three \\[universal-argument]'s searching starts at the beginning of the + current page. +With four \\[universal-argument]'s searching starts at the beginning of the + current buffer (clipping restrictions apply). + +Once located, the comment is copied into a temporary buffer, the comment +leaders and delimiters are stripped away and the resulting buffer is +selected for editing. The major mode of this buffer is controlled by +the variable `c-comment-edit-mode'.\\ + +Use \\[c-comment-edit-end] when you have finished editing the comment. The +comment will be inserted into the original buffer with the appropriate +delimiters and indention, replacing the old version of the comment. If +you don't want your edited version of the comment to replace the +original, use \\[c-comment-edit-abort]." + (interactive "*P") + (let ((c-buffer (current-buffer)) + marker tem c-comment-fill-column c-comment-buffer + c-comment-start c-comment-end + (inhibit-quit t)) + ;; honor search-prefix + (cond ((equal search-prefix '(4)) + (backward-paragraph)) + ((equal search-prefix '(16)) + (end-of-defun) + (beginning-of-defun) + (backward-paragraph)) + ((equal search-prefix '(64)) + (backward-page)) + ((equal search-prefix '(256)) + (goto-char (point-min)))) + (if (and (null search-prefix) (setq tem (within-c-comment-p))) + (setq c-comment-start (marker (car tem)) + c-comment-end (marker (cdr tem))) + (let (start end) + (condition-case error-data + (save-point + (search-forward "/*") + (setq start (- (point) 2)) + (search-forward "*/") + (setq end (point))) + (search-failed (error "No C comment found."))) + (setq c-comment-start (marker start)) + (setq c-comment-end (marker end)))) + ;; calculate the correct fill-column for the comment + (setq c-comment-fill-column (- fill-column 3 + (save-excursion + (goto-char c-comment-start) + (current-column)))) + ;; create the comment buffer + (setq c-comment-buffer + (generate-new-buffer (concat (buffer-name) " *C Comment Edit*"))) + ;; link into the c-comment-edit-buffer-alist + (setq c-comment-edit-buffer-alist + (cons (list (current-buffer) c-comment-buffer + c-comment-start c-comment-end) + c-comment-edit-buffer-alist)) + ;; copy to the comment to the comment-edit buffer + (copy-to-buffer c-comment-buffer (+ c-comment-start 2) (- c-comment-end 2)) + ;; mark the position of point, relative to the beginning of the + ;; comment, in the comment buffer. (iff point is within a comment.) + (or search-prefix (< (point) c-comment-start) + (setq marker (marker (+ (- (point) c-comment-start 2) 1) + c-comment-buffer))) + ;; select the comment buffer for editing + (switch-to-buffer c-comment-buffer) + ;; remove the comment leaders and delimiters + (goto-char (point-min)) + (while (not (eobp)) + (and (re-search-forward c-comment-leader-regexp nil t) + (replace-match "" nil t)) + (forward-line)) + ;; run appropriate major mode + (funcall (or c-comment-edit-mode 'fundamental-mode)) + ;; override user's default fill-column here since it will lose if + ;; the comment is indented in the C buffer. + (setq fill-column c-comment-fill-column) + ;; delete one leading whitespace char + (goto-char (point-min)) + (if (looking-at "[ \n\t]") + (delete-char 1)) + ;; restore cursor if possible + (goto-char (or marker (point-min))) + (if (fboundp 'set-keymap-parents) + (set-keymap-parents c-comment-edit-map (list (current-local-map)))) + (use-local-map c-comment-edit-map) + (set-buffer-modified-p nil)) + ;; run user hook, if present. + (if c-comment-edit-hook + (funcall c-comment-edit-hook)) + ;; final admonition + (message + (substitute-command-keys + "Type \\[c-comment-edit-end] to end edit, \\[c-comment-edit-abort] to abort with no change."))) + +(defun c-comment-edit-end () + "End c-comment-edit. +C comment is replaced by its edited counterpart in the appropriate C buffer. +Indentation will be the same as the original." + (interactive) + (let ((tuple (find-c-comment-buffer))) + (if (null tuple) + (error "Not a c-comment-edit buffer.")) + (let ((inhibit-quit t) + (c-comment-c-buffer (car tuple)) + (c-comment-buffer (nth 1 tuple)) + (c-comment-start (nth 2 tuple)) + (c-comment-end (nth 3 tuple))) + (cond + ((buffer-modified-p) + ;; rebuild the comment + (goto-char (point-min)) + (insert "/*\n") + (if (string= c-comment-leader " ") + (while (not (eobp)) + (if (not (eolp)) + (insert c-comment-leader " ")) + (forward-line)) + (while (not (eobp)) + (insert c-comment-leader (if (eolp) "" " ")) + (forward-line))) + (if (not (char-equal (preceding-char) ?\n)) + (insert "\n")) + (insert (if (string= c-comment-leader " *") " */" "*/")) + ;; indent if necessary + (let ((indention + (save-excursion + (set-buffer c-comment-c-buffer) + (goto-char c-comment-start) + (current-column)))) + (goto-char (point-min)) + (cond ((not (zerop indention)) + ;; first line is already indented + ;; in the C buffer + (forward-line) + (while (not (eobp)) + (indent-to indention) + (forward-line))))) + ;; replace the old comment with the new + (save-excursion + (set-buffer c-comment-c-buffer) + (save-point + (save-excursion + (delete-region c-comment-start c-comment-end) + (goto-char c-comment-start) + (set-buffer c-comment-buffer) + (append-to-buffer c-comment-c-buffer + (point-min) (point-max)))))) + (t (message "No change."))) + ;; switch to the C buffer + (if (get-buffer-window c-comment-c-buffer) + (select-window (get-buffer-window c-comment-c-buffer)) + (switch-to-buffer c-comment-c-buffer)) + ;; delete the window viewing the comment buffer + (and (get-buffer-window c-comment-buffer) + (delete-window (get-buffer-window c-comment-buffer))) + ;; unlink the tuple from c-comment-edit-buffer-alist + (setq c-comment-edit-buffer-alist + (delq tuple c-comment-edit-buffer-alist)) + ;; let Emacs reclaim various resources + (save-excursion + (set-buffer c-comment-buffer) + (set-buffer-modified-p nil) + (kill-buffer c-comment-buffer)) + (set-marker c-comment-start nil) + (set-marker c-comment-end nil)))) + +(defun c-comment-edit-abort () + "Abort a c-comment-edit with no change." + (interactive) + (let* ((tuple (find-c-comment-buffer)) + (c-comment-c-buffer (car tuple)) + (c-comment-buffer (nth 1 tuple)) + (c-comment-start (nth 2 tuple)) + (c-comment-end (nth 3 tuple))) + (if (null tuple) + (error "Not a c-comment-edit buffer.")) + ;; switch to the C buffer + (if (get-buffer-window c-comment-c-buffer) + (select-window (get-buffer-window c-comment-c-buffer)) + (switch-to-buffer c-comment-c-buffer)) + (let ((inhibit-quit t)) + (save-excursion + (set-buffer c-comment-buffer) + (set-buffer-modified-p nil) + (kill-buffer c-comment-buffer)) + ;; unlink the tuple from c-comment-edit-buffer-alist + (setq c-comment-edit-buffer-alist + (delq tuple c-comment-edit-buffer-alist)) + (set-marker c-comment-start nil) + (set-marker c-comment-end nil) + (message "Aborted with no change.")))) + +;; this loses on /* /* */ but doing it right would be grim. +(defun within-c-comment-p () + (condition-case error-data + (let (start end) + (save-point + (search-backward "/*") + (setq start (point)) + (search-forward "*/") + (setq end (point))) + (if (< (point) end) (cons start end) nil)) + (search-failed nil))) + +(defun find-c-comment-buffer (&optional buffer) + (or buffer (setq buffer (current-buffer))) + (let ((list c-comment-edit-buffer-alist)) + (catch 'return-value + (while list + (if (eq (nth 1 (car list)) buffer) + (throw 'return-value (car list)) + (setq list (cdr list))))))) + +(defun find-c-comment-c-buffer (&optional buffer) + (or buffer (setq buffer (current-buffer))) + (let ((list c-comment-edit-buffer-alist)) + (catch 'return-value + (while list + (if (eq (car (car list)) buffer) + (throw 'return-value (car list)) + (setq list (cdr list))))))) + +;; c-comment.el ends here diff --git a/xemacs-packages/lisp/c-support/c-comment-edit.elc b/xemacs-packages/lisp/c-support/c-comment-edit.elc new file mode 100644 index 0000000000000000000000000000000000000000..daf83511423f315247c77eca22f04f4a60c8d4c0 GIT binary patch literal 7156 zcmcgwYi}Io6^@EjdDj;a1W^dYJv$C~cjejj`tGDEc3ek-5`vOIs(6h&yZf$p;@O$W z%xoN2d`T1NIBkJ85=H$~RsCcer2d1Fi^H9SJK+wc*FVwcyfd>G+d)uOb)wnbd2i?P zoadbL?wfva>h^8hw#E1D+ebyKYU_q5QDKS9g$d2k%EHK;(mi2X8B=&Or#TrYcC zRJEe3+FEfzn-^}jsJb=Vwj2-NAW2o2o+?VZml1~CTu!G`*i45U1G&r)C2h?sRwy@` zBISWvwP4YailbL;g?>8Co701}qF&0#<%K0ru!4;pGSDHIw~tlmSNq4++(0nfvOT@3 z|4j4vEZv3X!F#WQA5uf8h1Yh`D&cdnqC<|7MW*GEIIX)L=_Um-kGKcG;uXAfm)WM~K?^h^v6(@(@wRkP*xtt+WeE0-a|O?T#HNyZOw2`!WtY3IeZ zOP726i)~lrbNyOycRB-Ty&i2Mmf}N#GqeG)orGcSQN?Z=wbH&U|9VquLSDLq!1~6c%~I% zR4ZwGftO3QqKLEe!XvSC3Ao%Fk7d)re+F$PlZjDUex&8cO;F6}gwqr+leoVEiic@`YRtWmcM1&iHqar6MpY-+ zLwRh5VzcRdKAF$siT{twXX?Hgn!PWAU2b4Fz}?6or4MQ+0O=}2NBRlux*-M;fb2VV z7(1>mStQaHXqVgddg8RF%CDi)xxvvu>)c2`r4Q6h7!3>tr9s7pJVqc;HVXhGuyC0; zBcvRy!&_bl6rHHSCqaFa&+?W(fZ)@LqAT%qnW`Fhe7lP!}5fx<}83% zI2W+y(HS>aJrGpYq<#$(tz(~X!G{+mMa=4e* z8(Otc(o~r*cqO0JDgv8avP7xo1Q|9WBL-V&9h{A%)Z5scdXvcMjs;flnMvNu+EKwO zEg|>6c=6KZw*6P8r;)yzfREU92C6a>gCjx}#ma^CU+%A;fz z?rKt38Y<8)m71mD5SF>|(Oha4Ug2~U3LE&lRZ!b<>0T};EK@T=xI*NMmtt)Pq_{Hq z5KluIg@G9|5Q39P@B@bq@j*Qkxxs<4ARAU|hNmO_nw%%={Epz|hy~p<8pA+j`wPuo zss|yAtz6Smcb3bNCULraKMVv+5mHZQr#sM Hu%< zE^~Rs1*|JHr-+^B8EuQ2QzBWNhA|L7#*$euUw)=$BCj~EW~h*_#{4kbwA%GF$8$+5 zb0(~!j=_!v)U3Q1RzaHA<{izhWP&Y`Ik(=jm;D=w6m9BB<4BG)dE`cp;1dnXxlpQ1t&ovf+GS3h@|afg4k@NplohUCarelG!ld) zk^u_z)1YO0eVPBRb`S2_efQ2gyZgF_+Fx2&ed1;ESN_=k%EIa|UnT!F^7;2~+h51X z8~En8zqzn_Ruug9wP&x<^7hqdu2XDc{lXpim|VYb+sg0Pm%G*O%v*22^R$1Rx-xR8 zOT|#SD|^1P;OnX5?;gMPz4z&ZhZDEk9i4geKv)0%9sM76bl%A4^X84?J=pv=bDhW5 zes!JZI*;EtezfDlj=qmN5XV;*%H7ENlD~4IYvhG9pON3TBa11Y zf00-{_vKd!zpL+sGx+`2uM?~O*Il{4(NtdX|K62L`2Sc>_?fn@fz@+e1LXhnU;j=d zI72n8hQ`-G4`kG;C}>2rsYvDyrp1;`V_{S@wvp^7D?B7=^fgSU%+RWx_%K&cU0BuYR^7G2T+nx(A5 z<6NM~jG&e^dF_%6JM@RFMp6$FT86uL8l-t)3Y1JjHN_(CQn+mm$x1b~Dq2%Yx3L)j>_SU0arCa8_fRYJ~Ya1xI;j}heKp**7S>)1mf~xdKsLr!iBit zKzbs#R&YJttI2*`mO8w@OUltD8$_@*U4lH=k4%q!Tg(aAf+cwsxV7_w^JqOJiYW zIxsXg2r5fItjx-yacGF9p?d3@OuSwTE2Vj+|`#7{>vQ`9g`EUbd0^) zF}8EpUAw#QeT~lkX&YGV^`akpV|f#oRk#C^|D?A-G>CguoUEaM zxG!?hVuft9j&@}vLT5hp+fGc-|D6#ELeu^yB24VvJV&RPWFa=E5PzcvzGNKoN0 zex1aMt*B;!6J2PkdWEyWP7y-|VcrtI&3RxnjLPBu@!=FFJsFfk{WQtHo(#>`Q7^pF zeFsDFO+fKFL-DQ7w!Cs{0LU1l^6hsLn?T7IGdJV47Qo&FpAFIL$P6I6H9i@5-wLDO z83V}TTe_S<-0XIVjymk5vp|R&yrZE0ZSXew^w8NO{kdG^?56txUagx=(P&3p_m>wh zJ}qkvzN6nK$dFk@6Z z(-B_HG1cI1skt1BJ^#Dd#N_J#wJ>HGNn!n-&v>s0K%=P?f?J) literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/c-fill.el b/xemacs-packages/lisp/c-support/c-fill.el new file mode 100644 index 00000000..48310bfb --- /dev/null +++ b/xemacs-packages/lisp/c-support/c-fill.el @@ -0,0 +1,272 @@ +;;; C comment mode - An auto-filled comment mode for gnu c-mode. +;;; +;;; Author: Robert Mecklenburg +;;; Computer Science Dept. +;;; University of Utah +;;; From: mecklen@utah-gr.UUCP (Robert Mecklenburg) +;;; Also hartzell@Boulder.Colorado.EDU +;;; (c) 1986, University of Utah +;;; +;;; Everyone is granted permission to copy, modify and redistribute +;;; this file, provided the people they give it to can. + +;;; Synched up with: Not in FSF. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; I have written a "global comment" minor-mode which performs auto-fill, +;;; fill-paragraph, and auto-indentation functions. This function only +;;; works for comments which occupy an entire line (not comments to the +;;; right of code). The mode has several options set through variables. +;;; If the variable c-comment-starting-blank is non-nil multi-line +;;; comments come out like this: +;;; +;;; /* +;;; * Your favorite +;;; * multi-line comment. +;;; */ +;;; +;;; otherwise they look like this: +;;; +;;; /* Your Favorite +;;; * multi-line comment. +;;; */ +;;; +;;; If the variable c-comment-hanging-indent is non-nil K&R style comments +;;; are indented automatically like this: +;;; +;;; /* my_func - For multi-line comments with hanging indent +;;; * the text is lined up after the dash. +;;; */ +;;; +;;; otherwise the text "the text" (!) is lined up under my_func. If a +;;; comment fits (as typed) on a single line it remains a single line +;;; comment even if c-comment-starting-blank is set. If +;;; c-comment-indenting is non-nil hitting carriage return resets the +;;; indentation for the next line to the current line's indentation +;;; (within the comment) like this: +;;; +;;; /* Typing along merrily.... +;;; * Now I indent with spaces, when I hit return +;;; * the indentation is automatically set to +;;; * ^ here. +;;; */ +;;; +;;; Due to my lack of understanding of keymaps this permanently resets M-q +;;; to my own fill function. I would like to have the comment mode +;;; bindings only in comment mode but I can't seem to get that to work. +;;; If some gnu guru can clue me in, I'd appreciate it. +;;; +(defvar c-comment-starting-blank t + "*Controls whether global comments have an initial blank line.") +(defvar c-comment-indenting t + "*If set global comments are indented to the level of the previous line.") +(defvar c-comment-hanging-indent t + "*If true, comments will be automatically indented to the dash.") +(defvar c-hang-already-done t + "If true we have performed the hanging indent already for this comment.") + + +;;; +;;; c-comment-map - This is a sparse keymap for comment mode which +;;; gets inserted when c-comment is called. +;;; +(defvar c-comment-mode-map () + "Keymap used in C comment mode.") +(if c-comment-mode-map + () + (setq c-comment-mode-map (copy-keymap c-mode-map)) + (define-key c-comment-mode-map "\e\r" 'newline) + (define-key c-comment-mode-map "\eq" 'set-fill-and-fill) + (define-key c-comment-mode-map "\r" 'set-fill-and-return)) + +;;; +;;; c-comment - This is a filled comment mode which can format +;;; indented text, do hanging indents, and symetric +;;; placement of comment delimiters. +;;; +(defun c-comment () + "Edit a C comment with filling and indentation. +This performs hanging indentation, symmetric placement of delimiters, + and Indented-Text mode style indentation. Type 'M-x apropos +c-comment' for information on options." + (interactive) + (let + ;; Save old state. + ((auto-fill-function (if c-comment-indenting + 'do-indented-auto-fill 'do-auto-fill)) +; (comment-start nil) + (comment-multi-line t) + (comment-start-skip "/*\\*+[ ]*") + (paragraph-start-ref paragraph-start) + fill-prefix paragraph-start paragraph-separate opoint) + + ;; Determine if we are inside a comment. + (setq in-comment + (save-excursion + (and (re-search-backward "/\\*\\|\\*/" 0 t) + (string= "/*" (buffer-substring (point) (+ (point) 2)))))) + + ;; Indent the comment and set the fill prefix to comment continuation + ;; string. If we are already in a comment get the indentation on + ;; the current line. + (setq c-hang-already-done nil) + + ;; Set the beginning of the comment and insert the blank line if needed. + (use-local-map c-comment-mode-map) + (if (not in-comment) + (progn (c-indent-line) + (insert "/* ") + (setq fill-prefix (get-current-fill (point))) + (recursive-edit) + + ;; If the comment fits on one line, place the close + ;; comment at the end of the line. Otherwise, newline. + (setq opoint (point)) + (if (and (save-excursion (beginning-of-line) + (search-forward "/*" opoint t)) + (<= (+ (current-column) 3) 79)) + (insert " */") + (insert "\n*/")) + + (c-indent-line)) + (progn (setq fill-prefix (get-current-fill (point))) + (recursive-edit) + (search-forward "*/" (buffer-size) t) + (forward-line 1))) + + ;; If starting blank enabled, insert a newline, etc., but only if + ;; this comment requires multiple lines. + (if c-comment-starting-blank + (save-excursion + (setq opoint (point)) + (forward-line -1) + (if (or (null (search-forward "/*" opoint t)) + (null (search-forward "*/" opoint t))) + (progn + (search-backward "/*") + (re-search-forward comment-start-skip opoint t) + (setq fill-prefix (get-current-fill (point))) + (if (not (looking-at "\n")) + (insert ?\n fill-prefix)))))) +; (indent-new-comment-line)))))) + + ;; Move cursor to indentation. + (c-indent-line) + (use-local-map c-mode-map) + ) + ) + + +;;; +;;; set-fill-and-fill - Get the current fill for this line and fill +;;; the paragraph. +;;; +(defun set-fill-and-fill (arg) + "Get the fill-prefix and fill the current paragraph." + + (interactive "P") + (setq fill-prefix (get-current-fill (point))) + (fill-paragraph arg)) + +;;; +;;; set-fill-and-return - Set the current fill prefix and +;;; indent-new-comment-line. +;;; +(defun set-fill-and-return () + "Set the current fill prefix and move to the next line." + + (interactive) + (if c-comment-indenting + (setq fill-prefix (get-current-fill (point)))) + (insert ?\n fill-prefix)) + +;;; +;;; do-indented-auto-fill - Perform the auto-fill function, but get +;;; the fill-prefix first. +;;; +(defun do-indented-auto-fill () + "Perform auto-fill, but get fill-prefix first." + + (let ((opoint (point))) + (save-excursion + (move-to-column (1+ fill-column)) + (skip-chars-backward "^ \t\n") + (if (bolp) + (re-search-forward "[ \t]" opoint t)) + ;; If there is a space on the line before fill-point, + ;; and nonspaces precede it, break the line there. + (if (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + + ;; If we are wrapping to a new line, figure out the indentation on + ;; the current line first. + (progn + (setq fill-prefix (get-current-fill opoint)) + (insert ?\n fill-prefix))))) +; (indent-new-comment-line))))) + ) + + +;;; +;;; get-current-fill - Get the fill-prefix for the current line. This +;;; assumes that the valid fill prefix is between +;;; (beginning-of-line) and (point). +;;; +(defun get-current-fill (pnt) + "Get the current fill prefix. +A valid fill prefix must be between the beginning of the line and point." + + (let ((opoint pnt) fill last-char) + (save-excursion + (beginning-of-line) + (setq fill + (buffer-substring (point) + (progn + (re-search-forward comment-start-skip opoint t) + (point)))) + + ;; Be sure there is trailing white space. + (setq last-char (substring fill (1- (length fill)) (length fill))) + (if (and (not (string= " " last-char)) + (not (string= " " last-char))) + (setq fill (concat fill " "))) + + (setq fill (replace-letter fill "/" " ")) + + ;; Get the hanging indentation if we haven't already. + (if (and c-comment-hanging-indent (not c-hang-already-done)) + (let ((curr (point)) + (opnt (progn (end-of-line) (point)))) + (beginning-of-line) + (if (search-forward " - " opnt t) + (progn + (setq fill (concat fill (make-string (- (point) curr) 32))) + (setq c-hang-already-done t))))) + + ;; Set the paragraph delimiters. + (setq paragraph-start (concat paragraph-start-ref + "\\|^" + (regexp-quote + (substring fill + 0 (1- (length fill)))) + "$")) + (setq paragraph-separate paragraph-start)) + fill) + ) + + +;;; +;;; replace-letter - Given a string, an old letter and a new letter, +;;; perform the substitution. +;;; +(defun replace-letter (str old-letter new-letter) + (let (new-str c + (sp 0) + (size (length str))) + (while (< sp size) + (setq c (substring str sp (1+ sp))) + (setq new-str (concat new-str (if (string= c old-letter) new-letter c))) + (setq sp (1+ sp))) + new-str)) diff --git a/xemacs-packages/lisp/c-support/c-fill.elc b/xemacs-packages/lisp/c-support/c-fill.elc new file mode 100644 index 0000000000000000000000000000000000000000..de9fc298657e16d866e392db69a7c8f84801405b GIT binary patch literal 3609 zcmZ`+S#KNH6*lrD(xw2nmK(1<9J&>$Xt-&&9^%3LV`p)fbjk8ddd{60E|OvcBWsKi;JM!O~=Vz}^ z&qFbvpOFfxuHA$xs(@U}b90uhYZm@uu9xGDoYSbOm6mB4Il(-U+h9#i_f$vI8(NKd zIbHQyj$^w5f1wU5%Pgr>ioqHxG0}dpke!CKqY1qZg}DqUueX{N8}8Iyv*{@C_AOEh zZ?tsN$ja-LwqO)kUqcps59Aif^}L#2Pz%LC+IEE5G~d+(*)lzhI5-z|e2|f0IC$*n zwt?U4brbzCY~Z#4wqbe#Ob&q$g@tT9o;ItH*0=%birwOd1LHx|VK|w14AQoHRK&6M z`t|FP46xy6yhH!eo^VZGQ!VCs4h*RUrI=STnM_>DG1o;CO1YQTaah;9ezmLkHgH+q zLZ`{2$X~tXx{M3evNc1sFv1L4X5t!m49^wj zrQz9WX;`=|HrbDE9U%-A46r5aCgKTO!D=7#!qB|>iP6?IUZY?GyM3ecQwu?~MZjRm zCakj{l@4>UluZf|;|mpp7D2OIrWtLZVoNZGX&o|7chpc)HEhm$b{A%5rP-+>{F1es zngiGe1}cY}QOMB5mKahORgPY$bO!+vR;`eqn?Z$X>Q1b%!9a=a{OQq1^6cZ-$DgG9 z$Fbc#`rJQA`Hvnba93A*TKbUaAK6Y@Z3K=Xa1cWD1j?m^0-UWArtsmOLgqGC_V zAE2Pf(5cHr%jK&uO`s|k7T}g)3eW}uT{lIY$N<&W5WtiM!j>eBYkKwg7go4vwYijM{;aXfO-OMcwY(vQWf+yNYuY(2wR@x4O@n5MM zpgFGX*j~JsqH$SplM^rkQbS%NlC!xN)=INXWP|bE6-eEsIw>RF4|ccT-`hVpec0)A zu3SxBx_tH8#j8KN`t!{vpFZ7BJ$z6ue^x5J_iQV3_VE1p^U-wDkL~>JbMU{={V&VO zb678b zYGm?=MIx{UY@&J%(*XwuUCq^;dT=N!t0E&*%?(VIZDMf@J8VQ|sMOE_bnvwQAVA4Y zlu8q?+=bZc1i}t;=rYw~nyc5<3QoCo%{5R6WlE*r;Ac*OJQV4gLfwQ6iyR^QL=UYY z-x6?h6QDp1ksDDiVGot#qi3!$l@UNgLs)2OXA0&P@D>?SN?d-?N2OJ*GFSD?cNr8w zEkxIP{`FmsG+DOYASTixK%8FFvW_+`2wn1Rsw%#;ZEpp(=)h;MY*1y zgXLfl$}&j;8#n*vO%T@(#oZ+{0ZPwSYoBt>7?JAa+70 z%530PD)*7%?DR}VR*ofSi0Rgceu6F zIrC&|=YHaFdF<1~)5Fx*=uf(TE%BYdly`sYmoL1G7e9LzJ4khZpLkv#`Ss@|WqIu2 zM-!tjfAM8vFR^szcJiw?JLfN)znDq9B4LHABQhxR=SeLd7Q)gzB(^%PdJ^JPfcyY) zMkS!!<9|%Q%jD3+y;tC + ;; Is this really the Whitesmith style? + (Alman + (c-argdecl-indent 0) + (c-brace-imaginary-offset 2) ;;; ???? + (c-brace-offset 0) + (c-continued-statement-offset 2) + (c-indent-level 0) + (c-label-offset -2) + (c-auto-newline t) + (comment-column 40) + (tab-width 2) + (fill-column '79)) + + (Gould + (c-indent-level 4) + (c-continued-statement-offset 4) + (c-brace-offset -4) + (c-argdecl-indent 8) + (c-label-offset -2) + (c-brace-imaginary-offset 0)) + + ;; From Joan Eslinger + (WRS + (c-indent-level 0) + (c-continued-statement-offset 4) + (c-brace-offset 0) + (c-argdecl-indent 4) + (c-label-offset -2) + (c-brace-imaginary-offset 4) + (c-continued-brace-offset -4)) + )) + +(defvar c-style nil + "The buffer local c-mode indentation style.") + +;; Add style name to mode line. Assumes minor-mode-alist is not buffer local. +;; Thanks to Joan Eslinger. + +(defvar c-style-name nil + "The style name for a c-mode indentation style. +This is to be set by set-c-style, and used by the mode line.") + +(or (assq 'c-style-name minor-mode-alist) + (setq minor-mode-alist + (purecopy + (append minor-mode-alist + ;; use undocumented feature + '((c-style-name c-style-name)))))) + +(defun set-c-style (&optional style) + "Set up the c-mode style variables from STYLE if it is given, or +default-c-style otherwise. It makes the c indentation style variables +buffer local." + + (interactive) + + (let ((c-styles (mapcar 'car c-style-alist))) ; for completion + (if (interactive-p) + (setq style + (let ((style-string ; Get style name with completion. + (completing-read + (format "Set c-mode indentation style to (default %s): " + default-c-style) + (vconcat c-styles) + (function (lambda (arg) (memq arg c-styles))) + ))) + (if (string-equal "" style-string) + default-c-style + (intern style-string)) + ))) + + ;; If style is nil, use default-c-style. + (setq style (or style default-c-style)) + + (make-local-variable 'c-style) + (if (memq style c-styles) + (setq c-style style) + (error "Undefined c style: %s" style) + ) + (message "c-style: %s" c-style) + + ;; Set the c-style-name + (make-local-variable 'c-style-name) + (setq c-style-name (format " %s" c-style)) + + ;; Finally, set the indentation style variables making each one local. + (mapcar (function (lambda (c-style-pair) + (make-local-variable (car c-style-pair)) + (set (car c-style-pair) + (car (cdr c-style-pair))))) + (cdr (assq c-style c-style-alist))) + c-style + )) diff --git a/xemacs-packages/lisp/c-support/c-style.elc b/xemacs-packages/lisp/c-support/c-style.elc new file mode 100644 index 0000000000000000000000000000000000000000..7d714b36c98edb0d10bf6b01adf460e73b6b7f31 GIT binary patch literal 3205 zcmb_eTW=Fb6z0(}iNr&wD)phqn?iOg);H{2UlQ5~l}1%XK(r!}81IhlQFdpxyR#1N zTSXD+Kj1eI)K{JZh?d^y{rB|D%x>eg4N;{=B-m%qob#RUoZ0iOZ*6}tf9A}Y^7{HZ zcp{8gKz-;8f$wjSm~?4S9WY6`sB$VnaJYq!ucZMrm!VN#t1qp!R-jq0w{?JSEJEmF z2&kn=TnmIp0{ledq{jDa(SFbEq%81jk|wftmxjbk+=zJlq(_sQ=O$?siCC&nav0Dm z4RloP2Lp`45J0n0ZGjyT>Gh$p?0|JG4LbsM`Y{V53qIRYQDHmvm|xY$J3~oTWhW7; z2;TUuE9`Z*zUnrb##=;^h3rcrRW6ob$;K}G_(hk7^`JTOgpdCp^cmvt1#lsO-erjd z#=&4{tX9iqn{~k^+y}cOQtn5vXv)sYamq7bi+J265?+68E%yOh{ElbTkDbVv@tzyd zB#EF97OZC7avZ0u{b(Fx3hT}ZuZwU%l9PUS@v*_Ik0ELWDF^JOaZI^%13`Q@z!Duy zP30Fb@c=jrFlo8Gu+d(D_iywm__RyXK*E3oDFxAm90b4)PL!q<85@c;hN`Zi`fl0A zQv(v`hu!Q9EMEQOCfEz_K^5GkdJ9w8s=Kc01z5+WE9agbS03MgcKm$TIy`=0!R<+i zSuB^RO8(7|)rw`gIbz$^**uqVUzbk@6z3j`_b?%sjHlGcNhOko>bdB4@p$IYiHS#Z zQ(d1SanGk-kcES`HU^|agWS(;I%vGI^Px&n$hvY`R^w2}>KfZvT4OAxT~TR2zIc5i zt-<()VvR#Ft+9=zH53%nwoSDYSzD(SYaEJMjcqKeF&4Ap)PTKxedm8kJGHaZvYN3W zsT3}!2La>M+!e4t4M^Ifc-_WYZbH9-`|+75@-bx~MolavJ;q5q%x7pdJvEG>22J{3PLsy}qQ~5Aw3fE>D{wbZ%_(iC1u_uBw zM~3U-{EkvH z!CPISx;16EPi1ckCUa&ClJWZwkj#M-Hpa_#oISYg;KpdRKrM_;+U??X(Aoi)MW|lw zrm1Ep8)Ozm~t$fGmlq0~J%ah`6Uo>Ia`W34InU5e83V~1^7rpNcJ&=jy~Be-2GXS@@R82zHkqt z6j>bM7#42Z7nKeZoCKh8qRe~o-OR4_jy!t!{mUPA`L6Zj*~(7~-@N_v!=rn<{L#H% zN)_k)+_zut^7F5rR}SaSCP!b-%|E*T>u+IH)1|km?i~dEi8Bo**JvXMrS2Gt93Dyoy)9VIW z4V+RvS}R>hoHejufS1O@gGdKnLZo1(lxR(35+{JxJ!tNMWg+R3#$5LSbsEZUHzyr3 z^>-6hOc%%02hTuWgA0iTA&N(o-(Y3s80+X9Arj??C~|8=Sd4IvOBV|xS^ Z3VIe#1EQerK|8;s?aND!+JSpc`5&9pC*uGB literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/cmacexp.el b/xemacs-packages/lisp/c-support/cmacexp.el new file mode 100644 index 00000000..c78214c5 --- /dev/null +++ b/xemacs-packages/lisp/c-support/cmacexp.el @@ -0,0 +1,389 @@ +;;; cmacexp.el --- expand C macros in a region + +;; Copyright (C) 1992, 1994, 1996 Free Software Foundation, Inc. + +;; Author: Francesco Potorti` +;; Version: $Id: cmacexp.el,v 1.2 2005/04/15 20:23:27 adrian Exp $ +;; Adapted-By: ESR +;; Keywords: c + +;; This file is part of XEmacs. + +;; XEmacs 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. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;;; Synched up with: FSF 19.34. + +;; USAGE ============================================================= + +;; In C mode C-C C-e is bound to c-macro-expand. The result of the +;; expansion is put in a separate buffer. A user option allows the +;; window displaying the buffer to be optimally sized. +;; +;; When called with a C-u prefix, c-macro-expand replaces the selected +;; region with the expansion. Both the preprocessor name and the +;; initial flag can be set by the user. If c-macro-prompt-flag is set +;; to a non-nil value the user is offered to change the options to the +;; preprocessor each time c-macro-expand is invoked. Preprocessor +;; arguments default to the last ones entered. If c-macro-prompt-flag +;; is nil, one must use M-x set-variable to set a different value for +;; c-macro-cppflags. + +;; A c-macro-expansion function is provided for non-interactive use. + +;; INSTALLATION ====================================================== + +;; Put the following in your ~/.emacs file. + +;; If you want the *Macroexpansion* window to be not higher than +;; necessary: +;;(setq c-macro-shrink-window-flag t) +;; +;; If you use a preprocessor other than /lib/cpp (be careful to set a +;; -C option or equivalent in order to make the preprocessor not to +;; strip the comments): +;;(setq c-macro-preprocessor "gpp -C") +;; +;; If you often use a particular set of flags: +;;(setq c-macro-cppflags "-I /usr/include/local -DDEBUG" +;; +;; If you want the "Preprocessor arguments: " prompt: +;;(setq c-macro-prompt-flag t) + +;; BUG REPORTS ======================================================= + +;; Please report bugs, suggestions, complaints and so on to +;; pot@cnuce.cnr.it (Francesco Potorti`). + +;; IMPROVEMENTS OVER emacs 18.xx cmacexp.el ========================== + +;; - A lot of user and programmer visible changes. See above. +;; - #line directives are inserted, so __LINE__ and __FILE__ are +;; correctly expanded. Works even with START inside a string, a +;; comment or a region #ifdef'd away by cpp. cpp is invoked with -C, +;; making comments visible in the expansion. +;; - All work is done in core memory, no need for temporary files. + +;; ACKNOWLEDGEMENTS ================================================== + +;; A lot of thanks to Don Maszle who did a great work of testing, bug +;; reporting and suggestion of new features. This work has been +;; partially inspired by Don Maszle and Jonathan Segal's. + +;; BUGS ============================================================== + +;; If the start point of the region is inside a macro definition the +;; macro expansion is often inaccurate. + + +(require 'cc-mode) + +(provide 'cmacexp) + +(defgroup c-macro nil + "Expand C macros in a region." + :group 'c) + + +(defcustom c-macro-shrink-window-flag nil + "*Non-nil means shrink the *Macroexpansion* window to fit its contents." + :type 'boolean + :group 'c-macro) + +(defcustom c-macro-prompt-flag nil + "*Non-nil makes `c-macro-expand' prompt for preprocessor arguments." + :type 'boolean + :group 'c-macro) + +(defcustom c-macro-preprocessor + ;; Cannot rely on standard directory on MS-DOS to find CPP. + (cond ((eq system-type 'ms-dos) "cpp -C") + ;; Solaris has it in an unusual place. + ((and (string-match "^[^-]*-[^-]*-\\(solaris\\|sunos5\\)" + system-configuration) + (file-exists-p "/opt/SUNWspro/SC3.0.1/bin/acomp")) + "/opt/SUNWspro/SC3.0.1/bin/acomp -C -E") + (t "/lib/cpp -C")) + "The preprocessor used by the cmacexp package. + +If you change this, be sure to preserve the `-C' (don't strip comments) +option, or to set an equivalent one." + :type 'string + :group 'c-macro) + +(defcustom c-macro-cppflags "" + "*Preprocessor flags used by `c-macro-expand'." + :type 'string + :group 'c-macro) + +(defconst c-macro-buffer-name "*Macroexpansion*") + +;; Autoload for XEmacs +;;;###autoload +(defun c-macro-expand (start end subst) + "Expand C macros in the region, using the C preprocessor. +Normally display output in temp buffer, but +prefix arg means replace the region with it. + +`c-macro-preprocessor' specifies the preprocessor to use. +Prompt for arguments to the preprocessor \(e.g. `-DDEBUG -I ./include') +if the user option `c-macro-prompt-flag' is non-nil. + +Noninteractive args are START, END, SUBST. +For use inside Lisp programs, see also `c-macro-expansion'." + + (interactive "r\nP") + (let ((inbuf (current-buffer)) + (displaybuf (if subst + (get-buffer c-macro-buffer-name) + (get-buffer-create c-macro-buffer-name))) + (expansion "")) + ;; Build the command string. + (if c-macro-prompt-flag + (setq c-macro-cppflags + (read-string "Preprocessor arguments: " + c-macro-cppflags))) + ;; Decide where to display output. + (if (and subst + (and buffer-read-only (not inhibit-read-only)) + (not (eq inbuf displaybuf))) + (progn + (message + "Buffer is read only: displaying expansion in alternate window") + (sit-for 2) + (setq subst nil) + (or displaybuf + (setq displaybuf (get-buffer-create c-macro-buffer-name))))) + ;; Expand the macro and output it. + (setq expansion (c-macro-expansion start end + (concat c-macro-preprocessor " " + c-macro-cppflags) t)) + (if subst + (let ((exchange (= (point) start))) + (delete-region start end) + (insert expansion) + (if exchange + (exchange-point-and-mark))) + (set-buffer displaybuf) + (setq buffer-read-only nil) + (buffer-disable-undo displaybuf) + (erase-buffer) + (insert expansion) + (set-buffer-modified-p nil) + (if (string= "" expansion) + (message "Null expansion") + (c-macro-display-buffer)) + (setq buffer-read-only t) + (setq buffer-auto-save-file-name nil) + (bury-buffer displaybuf)))) + + +;; Display the current buffer in a window which is either just large +;; enough to contain the entire buffer, or half the size of the +;; screen, whichever is smaller. Do not select the new +;; window. +;; +;; Several factors influence window resizing so that the window is +;; sized optimally if it is created anew, and so that it is messed +;; with minimally if it has been created by the user. If the window +;; chosen for display exists already but contains something else, the +;; window is not re-sized. If the window already contains the current +;; buffer, it is never shrunk, but possibly expanded. Finally, if the +;; variable c-macro-shrink-window-flag is nil the window size is *never* +;; changed. +(defun c-macro-display-buffer () + (goto-char (point-min)) + (c-mode) + (let ((oldwinheight (window-height)) + (alreadythere ;the window was already there + (get-buffer-window (current-buffer))) + (popped nil)) ;the window popped changing the layout + (or alreadythere + (progn + (display-buffer (current-buffer) t) + (setq popped (/= oldwinheight (window-height))))) + (if (and c-macro-shrink-window-flag ;user wants fancy shrinking :\) + (or alreadythere popped)) + ;; Enlarge up to half screen, or shrink properly. + (let ((oldwin (selected-window)) + (minheight 0) + (maxheight 0)) + (save-excursion + (select-window (get-buffer-window (current-buffer))) + (setq minheight (if alreadythere + (window-height) + window-min-height)) + ;; XEmacs change + (setq maxheight (/ (screen-height) 2)) + (enlarge-window (- (min maxheight + (max minheight + (+ 2 (vertical-motion (point-max))))) + (window-height))) + (goto-char (point-min)) + (select-window oldwin)))))) + + +(defun c-macro-expansion (start end cppcommand &optional display) + "Run a preprocessor on region and return the output as a string. +Expand the region between START and END in the current buffer using +the shell command CPPCOMMAND (e.g. \"/lib/cpp -C -DDEBUG\"). +Be sure to use a -C (don't strip comments) or equivalent option. +Optional arg DISPLAY non-nil means show messages in the echo area." + +;; Copy the current buffer's contents to a temporary hidden buffer. +;; Delete from END to end of buffer. Insert a preprocessor #line +;; directive at START and after each #endif following START that are +;; not inside a comment or a string. Put all the strings thus +;; inserted (without the "line" substring) in a list named linelist. +;; If START is inside a comment, prepend "*/" and append "/*" to the +;; #line directive. If inside a string, prepend and append "\"". +;; Preprocess the buffer contents, then look for all the lines stored +;; in linelist starting from end of buffer. The last line so found is +;; where START was, so return the substring from point to end of +;; buffer. + (let ((inbuf (current-buffer)) + (outbuf (get-buffer-create " *C Macro Expansion*")) + (filename (if (and buffer-file-name + (string-match (regexp-quote default-directory) + buffer-file-name)) + (substring buffer-file-name (match-end 0)) + (buffer-name))) + (mymsg (format "Invoking %s%s%s on region..." + c-macro-preprocessor + (if (string= "" c-macro-cppflags) "" " ") + c-macro-cppflags)) + (uniquestring "??? !!! ??? start of c-macro expansion ??? !!! ???") + (startlinenum 0) + (linenum 0) + (startstat ()) + (startmarker "") + (exit-status 0) + (tempname (make-temp-name (concat + (or (getenv "TMPDIR") (getenv "TEMP") + (getenv "TMP") "/tmp") + "/")))) + (unwind-protect + (save-excursion + (save-restriction + (widen) + (let ((in-syntax-table (syntax-table))) + (set-buffer outbuf) + (setq buffer-read-only nil) + (erase-buffer) + (set-syntax-table in-syntax-table)) + (insert-buffer-substring inbuf 1 end)) + + ;; We have copied inbuf to outbuf. Point is at end of + ;; outbuf. Inset a newline at the end, so cpp can correctly + ;; parse a token ending at END. + (insert "\n") + + ;; Save sexp status and line number at START. + (setq startstat (parse-partial-sexp 1 start)) + (setq startlinenum (+ (count-lines 1 (point)) + (if (bolp) 1 0))) + + ;; Now we insert the #line directives after all #endif or + ;; #else following START going backward, so the lines we + ;; insert don't change the line numbers. + ;(switch-to-buffer outbuf) (debug) ;debugging instructions + (goto-char (point-max)) + (while (re-search-backward "\n#\\(endif\\|else\\)\\>" start 'move) + (if (equal (nthcdr 3 (parse-partial-sexp start (point) + nil nil startstat)) + '(nil nil nil 0 nil)) ;neither in string nor in + ;comment nor after quote + (progn + (goto-char (match-end 0)) + (setq linenum (+ startlinenum + (count-lines start (point)))) + (insert (format "\n#line %d \"%s\"\n" linenum filename)) + (goto-char (match-beginning 0))))) + + ;; Now we are at START. Insert the first #line directive. + ;; This must work even inside a string or comment, or after a + ;; quote. + (let* ((startinstring (nth 3 startstat)) + (startincomment (nth 4 startstat)) + (startafterquote (nth 5 startstat)) + (startinbcomment (nth 7 startstat))) + (insert (if startafterquote " " "") + (cond (startinstring + (char-to-string startinstring)) + (startincomment "*/") + ("")) + (setq startmarker + (concat "\n" uniquestring + (cond (startinstring + (char-to-string startinstring)) + (startincomment "/*") + (startinbcomment "//")) + (if startafterquote "\\"))) + (format "\n#line %d \"%s\"\n" startlinenum filename))) + + ;; Call the preprocessor. + (if display (message mymsg)) + (setq exit-status + (call-process-region 1 (point-max) + shell-file-name + t (list t tempname) nil + shell-command-switch cppcommand)) + (if display (message (concat mymsg "done"))) + (if (= (buffer-size) 0) + ;; Empty output is normal after a fatal error. + (insert "\nPreprocessor produced no output\n") + ;; Find and delete the mark of the start of the expansion. + ;; Look for `# nn "file.c"' lines and delete them. + (goto-char (point-min)) + (search-forward startmarker) + (delete-region 1 (point))) + (while (re-search-forward (concat "^# [0-9]+ \"" + (regexp-quote filename) + "\"") nil t) + (beginning-of-line) + (let ((beg (point))) + (forward-line 1) + (delete-region beg (point)))) + + ;; If CPP got errors, show them at the beginning. + ;; MS-DOS shells don't return the exit code of their children. + ;; Look at the size of the error message file instead, but + ;; don't punish those MS-DOS users who have a shell that does + ;; return an error code. + (or (and (or (not (boundp 'msdos-shells)) + (not (member (file-name-nondirectory shell-file-name) + msdos-shells))) + (eq exit-status 0)) + (zerop (nth 7 (file-attributes (expand-file-name tempname)))) + (progn + (goto-char (point-min)) + ;; Put the messages inside a comment, so they won't get in + ;; the way of font-lock, highlighting etc. + (insert + (format "/* Preprocessor terminated with status %s\n\n Messages from `%s\':\n\n" + exit-status cppcommand)) + (goto-char (+ (point) + (nth 1 (insert-file-contents tempname)))) + (insert "\n\n*/\n"))) + (delete-file tempname) + + ;; Compute the return value, keeping in account the space + ;; inserted at the end of the buffer. + (buffer-substring 1 (max 1 (- (point-max) 1)))) + + ;; Cleanup. + (kill-buffer outbuf)))) + +;;; cmacexp.el ends here diff --git a/xemacs-packages/lisp/c-support/cmacexp.elc b/xemacs-packages/lisp/c-support/cmacexp.elc new file mode 100644 index 0000000000000000000000000000000000000000..807690164b6bd016ef94d46bd7398003f6eaa13f GIT binary patch literal 5342 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 +;; Maintainer: Anders Lindgren +;; Version: 1.2 +;; Created: 16 Mar 1997 +;; Date: 12 Jun 1997 + +;; CTypes 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. + +;; CTypes 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. + +;;; Commentary: + +;;{{{ Documentation + +;; Background: +;; +;; As most Emacs users know, Emacs can fontify source code buffers +;; using the `font-lock' package. Most of the time it does a really +;; good job. Unfortunately, the syntax of one of the most widely +;; spread languages, C, makes it difficult to fontify variable +;; declarations. For example, what does the following line mean: +;; +;; hello(foo * bar); +;; +;; a) A new function `hello' that takes one argument `bar' that is a +;; pointer to a `foo', or; +;; +;; b) call the function `hello' with the result of `foo' multiplied +;; by `bar'. +;; +;; To answer the question correctly you must know whether `foo' is a +;; type or not. Unfortunately, font-lock has no way of knowing this. + +;; This package: +;; +;; This package can search through source files hunting down typedefs. +;; When found, font-lock is informed and your source code will be even +;; more beautifully colored than before. +;; +;; Each major mode has it's own set of types. It is possible for one +;; major mode to inherit the types of another mode. +;; +;; Currently, this package can parse C and C++ files. (However, since +;; I do not use C++, the probability is high (about 12, on a scale +;; from 1 to 12) that I've missed something). By default C++ inherits +;; the types defined for C mode. + +;; Installation: +;; +;; Place this file in any directory in the emacs load path +;; and add the following line to your init file: +;; (require 'ctypes) +;; +;; Or, if you should prefer to load ctypes only when needed: +;; +;; (defun my-activate-ctypes () (require 'ctypes)) +;; (add-hook 'c-mode-hook 'my-activate-ctypes) +;; (add-hook 'c++-mode-hook 'my-activate-ctypes) +;; +;; Of course, you must also activate font-lock. I also recomend using +;; lazy-lock since adding types requires refontification of all +;; buffers. (Should you use many small buffers, consider lowering +;; `lazy-lock-minimum-size' aswell.) + +;; Defining types: +;; +;; The following commands are available to define and remove types: +;; +;; ctypes-define-type Add a type. +;; ctypes-define-type-in-mode Add a type to another major mode. +;; ctypes-buffer Scan a buffer for types. +;; ctypes-all-buffer Scan all buffer for types. +;; ctypes-tags Search through all files in a TAGS table. +;; ctypes-dir Search a directory hierarchy for files. +;; ctypes-file Search in a file for types. +;; ctypes-remove-type Remove one type. +;; ctypes-remove-type-in-mode Remove one type in another mode. +;; ctypes-clear-types Forget all types. +;; ctypes-clear-types-all-modes Forget all types in all major modes. + +;; Edit types: +;; +;; If you would like to view or change the types found you can use the +;; function `ctypes-edit'. When done press C-c C-c. Should you like +;; do discard your changes just kill the buffer with C-x k. +;; +;; To edit the types for another major mode use the command +;; `ctypes-edit-types-for-mode'. + +;; Saving types: +;; +;; The commands `ctypes-write-file' and `ctypes-read-file' can be used +;; to save your hard-earned collection of types to a file and to +;; retrieve it later. +;; +;; The default file name is stored in the variable `ctypes-file-name'. +;; +;; Note that only one collection of types are managed. Should you +;; prefer to keep one type file per project, remember to clear the set +;; of known types (using the command `ctypes-clear-types-all-modes') +;; before each new set is generated. + +;; At Load: +;; +;; It is possible to automatically add new types, or read specific +;; type files, when Emacs opens a file. +;; +;; By adding a "Local Variables" section to the end of the file +;; containing the variables `ctypes-add-types-at-load' and/or +;; `ctypes-read-files-at-load' this can be accomplished. +;; +;; For example: +;; +;; /* +;; * Local Variables: +;; * ctypes-add-types-at-load: ("MyType" "YourType") +;; * ctypes-read-files-at-load: (".ctypes") +;; * End: +;; */ + +;; The `Auto Parse' mode: +;; +;; This package can automatically search for new types in all visited +;; files. Activate the minor mode `ctypes-auto-parse-mode' to enable +;; this feature. +;; +;; Add the following line to your startup file to automatically +;; scan all visited files: +;; (ctypes-auto-parse-mode 1) + +;; Example 1: +;; +;; The following setup is for the really lazy person. The keywords +;; collected during one session will be kept for the next, and all +;; visited files will be parsed in the boldly search for new types. +;; I would recomend using this approach only when you are keeping all +;; your types in one file. +;; +;; (require 'ctypes) +;; (setq ctypes-write-types-at-exit t) +;; (ctypes-read-file nil nil t t) +;; (ctypes-auto-parse-mode 1) + +;; Example 2: +;; +;; In this example, ctypes will not be not loaded until either c-mode +;; or c++-mode is activated. When loaded, ctypes will read the type +;; file "~/.ctypes_std_c" (containing, for example, all types defined +;; in the standard C header files). +;; +;; (defun my-c-mode-hook () +;; (require 'ctypes) +;; (turn-on-font-lock)) +;; (add-hook 'c-mode-hook 'my-c-mode-hook) +;; (add-hook 'c++-mode-hook 'my-c-mode-hook) +;; +;; (defun my-ctypes-load-hook () +;; (ctypes-read-file "~/.ctypes_std_c" nil t t)) +;; (add-hook 'ctypes-load-hook 'my-ctypes-load-hook) + +;; Home Page: +;; +;; You can always find the latest version of this package on my Emacs +;; page: +;; +;; http://www.csd.uu.se/~andersl/emacs.shtml + +;; Reporting bugs: +;; +;; Out of the last ten bugs you found, how many did you report? +;; +;; When reporting a bug, please: +;; +;; * Send a mail the maintainer of the package, or to the author +;; if no maintainer exists. +;; * Include the name of the package in the title of the mail, to +;; simplify for the recipient. +;; * State exactly what you did, what happened, and what you expected +;; to see when you found the bug. +;; * If possible, include an example that activates the bug. +;; * Should you speculate about the cause of the problem, please +;; state explicitly that you are guessing. + +;; CTypes, the true story: +;; +;; Well, brave reader, are you willing to learn what this package +;; really is capable of? +;; +;; Basically, it is a general purpose parsing package. The default +;; settings just happened to specify a parser that looks for C +;; typedefs, and that the default action is to add the types found to +;; font-lock. +;; +;; Be redefining the variable `ctypes-mode-descriptor' you can change +;; the behavior totally. For example, you can use it to search for +;; all occurrences of XX (replace XX with whatever you like) in all +;; files edited in major mode YY (ditto for YY) and to perform ZZ-top +;; whenever a new XX is found. (However, it might be difficult for +;; Emacs to grow a beard). +;; +;; I will, however, in the document string, write "search for types" +;; when I really mean "Call the parser routine as specified by +;; `ctypes-mode-descriptor'". Also, I write "Informing font-lock" +;; whenever I mean "Performing the default action as specified in +;; `ctypes-mode-descriptor'". + +;; The future: +;; +;; Should this package be included in Emacs 19.35 almost all of the +;; font-lock code could be removed. Also there will be no need to +;; load font-lock to determine which version of ctypes-mode-descriptor +;; to use. + +;;}}} + +;;; Code: + +;;{{{ Dependencies + +;; The only reason to load font-lock is to determine the font-lock +;; version we are using. + +(require 'font-lock) + +(eval-when-compile + (require 'cl)) + +;;}}} +;;{{{ Variables + +(defvar ctypes-file-name "~/.ctypes" + "*Default name of file to read types from. + +When `ctypes-read-file' and `ctypes-write-file' are called interactively +the directory part of the file name is ignored.") + + +(defvar ctypes-write-types-at-exit nil + "*When non-nil types are saved to file when Emacs exits. + +When this variable be 'ask, the user is prompted before the +types are saved.") + + +(defvar ctypes-mode-descriptor + (if (boundp 'c-font-lock-extra-types) + ;; This version of the mode descriptor needs font-lock from + ;; Emacs 19.35. + '((c-mode + (parser ctypes-parse-buffer-c) + (action ctypes-font-lock-set-extra-types + c-font-lock-extra-types)) + (c++-mode + (inherit c-mode) + (parser ctypes-parse-buffer-c++) + (action ctypes-font-lock-set-extra-types + c++-font-lock-extra-types))) + ;; The following can be used together with good old font-lock from + ;; XEmacs and GNU Emacs up to, and including, 19.34. + '((c-mode + (parser ctypes-parse-buffer-c) + (action ctypes-font-lock-add-keywords + ((1 c-font-lock-keywords-2) + (1 c-font-lock-keywords-3) + (2 c-font-lock-keywords-3 t)))) + (c++-mode + (inherit c-mode) + (parser ctypes-parse-buffer-c++) + (action ctypes-font-lock-add-keywords + ((1 c++-font-lock-keywords-2) + (1 c++-font-lock-keywords-3) + (2 c++-font-lock-keywords-3 t)))))) + "*Describe parser, action, and inheritance structure of major mode. + +This structure should be a list where each element should be on +the following form: + ( + (inherit ) + (parser ) + (action function [Optional extra arguments])) + +The function specified in the `action' field is called with at least +one arguments, the major mode. Should the function in the action +field be followed by anything it will be used as additional arguments +when the function is called.") + + +(defvar ctypes-dir-read-file nil + "*Variable determining which files `ctypes-dir' should read. + +When search for types in a large number of files it is difficult +to determine which files to parse. Should too few be opened, we +can miss some types. The opposite, to open to many be opened, +the parse process could take much longer than needed. + +The default behavior, when `ctypes-dir-read-file' is nil, is to look +at the extension of the files found. Should it match a major mode in +`auto-mode-alist', and the major mode is in `ctypes-mode-descriptor' +we read the file. Obviously, this approach is fast but it is possible +to miss files. + +After the file has been read the real major mode is determined from +the content of the file. This allows you to specify the real mode +using the -*- mode -*- construction. + +Should this variable be t, all non-backup files are read. + +Please see the variable `ctypes-dir-backup-files' for a description on +how backup files are treated. + +To open only a few extra files, bind this variable to a regexp. + +For example, when using the following setting `ctypes-dir' will +open all files ending in `.cplusplus'. + + (setq ctypes-dir-read-file \"\\\\.cplusplus\\\\'\") + +However, the files would still need a -*- C++ -*- header line +to be parsed as C++ files.") + + +(defvar ctypes-dir-backup-files nil + "*Non-nil means that `ctypes-dir' should parse backup files.") + +(defvar ctypes-auto-parse-mode nil + "Non-nil when the minor mode `ctypes-auto-parse-mode' is enabled. + +When this mode is active the `ctypes' package will search for +types in all new buffers loaded. + +To start the mode call the function `ctypes-auto-parse-mode', do not +set this variable explicitly.") + + +(defvar ctypes-auto-parse-mode-hook nil + "*List of functions to run when `ctypes-auto-parse-mode' is activated.") + +(defvar ctypes-load-hook nil + "*List of functions to run when `ctypes' is loaded.") + + +(defvar ctypes-saved-p t + "Nil when types not saved to file.") + + +(defvar ctypes-repetitive-type-regexp + (concat "\\<\\(short\\|int\\|long\\|float\\|" + "double\\|char\\|\\(un\\)?signed\\|const\\)\\>") + "Regexp matching C types and modifiers that can be combined. + +Example: `unsigned char'") + + +;; In some environments the $-sign can be part of C identifiers. +(defvar ctypes-identifier-regexp "[a-zA-Z_][a-zA-Z0-9_$:]*" + "Regexp matching C identifiers.") + + +;; Useful during debug and development. +(defvar ctypes-parse-error nil + "(File pos) of latest error, or nil.") + +;;}}} +;;{{{ Commands + +;;;###autoload +(defun ctypes-define-type (type &optional delay-action mode) + "Add a new TYPE to current major mode and inform font-lock. + +When preceded by C-u the display is not updated. + +Return non-nil if the type was not known before." + (interactive + (list + (let* ((default (ctypes-get-type-under-point)) + (prompt (if default + (format "Type: (default %s) " default) + "Type: ")) + (spec (read-string prompt))) + (if (equal spec "") default spec)) + prefix-arg)) + (if (equal type "") + (error "Can't define \"\" as a type")) + (or mode + (setq mode major-mode)) + (and type + (> (length type) 0) + (let ((added (ctypes-add-types mode (list type)))) + (ctypes-perform-action mode added delay-action) + added))) + + +;; Designed for interactive use only. +;;;###autoload +(defun ctypes-define-type-in-mode (type &optional delay-action mode) + "Add TYPE to major mode MODE and inform font-lock. + +When preceded by C-u the display is not updated. + +\(This function is designed for interactive use, please call +`ctypes-define-type' from Lisp programs.)" + (interactive "sType: \nP\nsIn mode: ") + (ctypes-define-type type delay-action (ctypes-string-to-mode mode))) + + +;;;###autoload +(defun ctypes-buffer (&optional buf delay-action mode) + "Search for types in buffer, inform font-lock if any is found. + +When preceded by C-u the action is not performed. + +Return non-nil if new types are found." + (interactive "bSearch for types in buffer: \nP") + (save-excursion + (if buf + (set-buffer buf) + (setq buf (current-buffer))) + (or mode + (setq mode major-mode))) + (let ((added (ctypes-add-types mode (ctypes-parse-buffer buf mode)))) + (ctypes-perform-action mode added delay-action) + added)) + + +;;;###autoload +(defun ctypes-all-buffers (&optional delay-action) + "Search for types in all buffers, inform font-lock about all discoveries. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." + (interactive "P") + (save-excursion + (let ((modes '()) + (added nil)) + (dolist (buf (buffer-list)) + (set-buffer buf) + (if (assq major-mode ctypes-mode-descriptor) + (if (not (ctypes-buffer nil t)) + () + (setq added t) + (if (not (memq major-mode modes)) + (setq modes (cons major-mode modes)))))) + (ctypes-perform-action modes added delay-action) + added))) + + +;;;###autoload +(defun ctypes-tags (&optional delay-action) + "Search for types in files in the visited TAGS table. +Should no tags table be visited, the user will be prompted for a new. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." + (interactive "P") + (let ((modes (ctypes-tags-parse))) + (ctypes-perform-action modes t delay-action) + (not (null modes)))) + + +;;;###autoload +(defun ctypes-dir (&optional dir delay-action) + "Search for types in files in a directory hierarchy. + +See variable `ctypes-dir-read-file' for a description of which files +are opened during scanning, and how you can change the behavior. + +When preceded by C-u the display is not updated. + +Return non-nil if new types are found." + (interactive "DSearch in directory: \nP") + (if (null dir) + (setq dir default-directory)) + (let ((dirs (list dir)) + (modes '())) + (while dirs + (setq dir (car dirs)) + (setq dirs (cdr dirs)) + (dolist (file (directory-files dir t)) ; Files and dirs + (cond + ((file-accessible-directory-p file) + (if (and (not (string= (file-name-nondirectory file) ".")) + (not (string= (file-name-nondirectory file) ".."))) + (setq dirs (cons file dirs)))) + ((file-readable-p file) + (if (or ctypes-dir-backup-files + (not (backup-file-name-p file))) + (if (or (eq ctypes-dir-read-file t) + (and (stringp ctypes-dir-read-file) + (string-match ctypes-dir-read-file file)) + (assq (ctypes-get-mode-from-file-name file) + ctypes-mode-descriptor)) + (let ((mode (ctypes-file file t))) + (if mode + (setq modes (cons mode modes)))))))))) + (and modes + (ctypes-perform-action modes t delay-action)))) + + +;;;###autoload +(defun ctypes-file (file &optional delay-action) + "Search for types in file FILE. +Should FILE not be loaded it is read into a temporary buffer. + +Return mode of file, if new types was found." + (interactive "fSearch in file: \nP") + ;; (message "Scanning %s..." file) ; Debug + (let ((added nil) + mode) + (save-excursion + (cond ((get-file-buffer file) + (set-buffer (find-file-noselect file t)) + (setq mode major-mode) + (setq added (ctypes-buffer nil t mode))) + (t + (set-buffer (get-buffer-create " *ctypes-file*")) + (kill-all-local-variables) + (erase-buffer) + (insert-file-contents file nil) + (let ((buffer-file-name file)) + (setq mode (ctypes-get-mode)) + (if mode + (setq added (ctypes-buffer nil delay-action mode)))) + (kill-buffer (current-buffer))))) + ;; (message "Scanning %s...done" file) ; Debug + (if mode + (ctypes-perform-action mode added delay-action)) + (and added mode))) + + +(defun ctypes-remove-type (type &optional delay-action mode) + "Remove TYPE from the set of known types for major mode of current buffer. + +When preceded by C-u the display is not updated. + +Return non-nil if type is removed." + (interactive + (list + (let* ((default (ctypes-get-type-under-point)) + (prompt (if default + (format "Type: (default %s) " default) + "Type: ")) + (spec (read-string prompt))) + (if (equal spec "") default spec)) + prefix-arg)) + (or mode + (setq mode major-mode)) + (let ((removed (ctypes-delete-types mode (list type)))) + (ctypes-perform-action mode removed delay-action) + removed)) + + +;; Designed for interactive use only. +(defun ctypes-remove-type-in-mode (type &optional delay-action mode) + "Remove TYPE from the set of known types for major mode MODE. + +MODE can either be a symbol (e.g. c++-mode), or a string (e.g. \"C++\"). + +When preceded by C-u the display is not updated. + +Return non-nil if type is removed." + (interactive "sType: \nP\nsIn mode: ") + (ctypes-remove-type type delay-action (ctypes-string-to-mode mode))) + + +(defun ctypes-clear-types (&optional delay-action) + "Clear all known types for major mode of current buffer. + +When preceded by C-u the display is not updated. + +Return non-nil if any types actually were removed." + (interactive "P") + (setq ctypes-parse-error nil) ; Debug + (let ((removed (ctypes-set-types major-mode '()))) + (ctypes-perform-action major-mode removed delay-action) + removed)) + + +(defun ctypes-clear-types-all-modes (&optional delay-action) + "Clear all types for all modes. + +When preceded by C-u the display is not updated. + +Return non-nil if any types actually were removed." + (interactive "P") + (setq ctypes-parse-error nil) ; Debug + (let ((modes '())) + (dolist (desc ctypes-mode-descriptor) + (if (ctypes-set-types (car desc) '()) + (setq modes (cons (car desc) modes)))) + (if modes + (ctypes-perform-action modes t t)) + (or delay-action + (ctypes-perform-delayed-action)) + (not (null modes)))) + + +(defun ctypes-update () + "Make sure no delayed action is pending for types of major mode. + +Since it can take some time to re-fontify all buffers after every +command it is possible to inhibit redisplay by preceding the command +by C-u. This command can be used to refontify all buffers after a +number of such commands." + (ctypes-perform-action major-mode nil t)) + + +(defun ctypes-update-all-modes () + "Make sure no delayed action is pending for any major mode. + +Since it can take some time to re-fontify all buffers after every +command it is possible to inhibit redisplay by preceding the command +by C-u. This command can be used to refontify all buffers after a +number of such commands." + (ctypes-perform-delayed-action)) + +;;}}} +;;{{{ Minor mode: ctypes-auto-parse-mode + +;;;###autoload +(defun ctypes-auto-parse-mode (&optional arg) + "Toggle CTypes auto parse mode; search all new buffers for types. +With arg, turn types Auto Mode on if and only if arg is positive. + +This a global minor mode, it does not have a private keymap, nor does +it add itself to the mode line. + +Place the following in your startup file to enable this feature in +future sessions: + + (require 'ctypes) + (ctypes-auto-parse-mode 1) + +When activated, the functions in the hook `ctypes-auto-parse-mode-hook' +is called with no args." + (interactive "P") + (setq ctypes-auto-parse-mode + (if (null arg) + (not ctypes-auto-parse-mode) + (> (prefix-numeric-value arg) 0))) + (if ctypes-auto-parse-mode + (run-hooks 'ctypes-auto-parse-mode-hook))) + +;;}}} +;;{{{ Find-file hook + +(defvar ctypes-add-types-at-load '() + "List of types to be added when file is opened. + +This variable is designed to be used in a \"Local Variables\" section +at the end of source files.") + + +(defvar ctypes-read-files-at-load '() + "CTypes files to be read when file is opened. + +This variable could either be the name of a type file, or a list of +type files. + +This variable is designed to be used in a \"Local Variables\" section +at the end of source files. Should this variable not be defined in a +Local Variables section, the global value is used. By setting this +variable to, for example, \".ctypes\" Emacs will try to read a type file +named \".ctypes\" in every directory it opens files from.") + + +(defun ctypes-find-file-hook () + "Add types specified in file local variables. + +This function is called every time a file is opened. It looks at two +variables `ctypes-add-types-at-load' and `ctypes-read-files-at-load'. +They are designed to be added to the \"Local Variables:\" section at +the end of source files. The idea is to automatically set or load +the types needed when a file is opened. + +When `ctypes-auto-parse-mode' is active this function will parse +the content of the buffer looking for types." + (let ((added nil)) + (if (and ctypes-add-types-at-load + (ctypes-add-types major-mode ctypes-add-types-at-load)) + (setq added t)) + (dolist (file (or (and (stringp ctypes-read-files-at-load) + (list ctypes-read-files-at-load)) + ctypes-read-files-at-load)) + (if (and (stringp file) + (ctypes-read-file file nil t)) + (setq added t))) + (if ctypes-auto-parse-mode + (ctypes-buffer nil t)) + (ctypes-perform-action major-mode added nil))) + +;;}}} +;;{{{ Read and write + +;;;###autoload +(defun ctypes-read-file (&optional file delay-action no-error quietly) + "Load types previously saved with `ctypes-write-file'. +The name of the file is given by the optional argument FILE. +Should no file name be given the value of the variable `ctypes-file-name' +is used. + +Please note that the types read will be added to the current types. + +When preceded by C-u the display is not updated. + +The third argument, NO-ERROR, determines whether or not we should +raise an error if there should be any problem loading the file. + +Should the fourth argument, QUIETLY, be non-nil no messages are +generated when the file is loaded. + +Return non-nil if new types are found." + (interactive + (list + (ctypes-interactive-read-file-name "Read types from file: ") + current-prefix-arg)) + (setq file (ctypes-gen-file-name file)) + (let ((current-types-alist '())) + (dolist (desc ctypes-mode-descriptor) + (let ((mode (car desc))) + (setq current-types-alist + (cons (cons mode (ctypes-get-types mode)) + current-types-alist)))) + (load file no-error quietly) + (setq ctypes-saved-p t) + ;; Add the original types, and update wherever needed. + (let ((modes '())) ; Updated modes + (dolist (pair current-types-alist) + (if (not (ctypes-subset + (ctypes-get-types (car pair)) + (cdr pair))) + ;; New types was defined for this mode. + (setq modes (cons (car pair) modes))) + (ctypes-add-types (car pair) (cdr pair))) + (if modes + (ctypes-perform-action modes t delay-action)) + modes))) + + +(defun ctypes-write-file (&optional file) + "Write all types to a file. +The file is readable by the function `ctypes-read-file'. + +Should no file name be given, the value of the variable `ctypes-file-name' +is used." + (interactive + (list + (ctypes-interactive-read-file-name "Write types file: "))) + (setq file (ctypes-gen-file-name file)) + (save-excursion + (set-buffer (get-buffer-create " *ctypes-write-file*")) + (erase-buffer) + (insert ";; This file has been automatically generated by the ") + (insert "Emacs package `ctypes'.\n") + (insert ";; Please use the `ctypes-read-file' to load it.\n\n") + (dolist (desc ctypes-mode-descriptor) + (insert "(ctypes-set-types '") + (insert (prin1-to-string (car desc))) + (insert " '") + (insert (prin1-to-string (ctypes-get-types (car desc)))) + (insert ")\n\n")) + (write-region 1 (point-max) file) + (erase-buffer)) + (setq ctypes-saved-p t)) + + +(defun ctypes-kill-emacs-hook (&optional file) + "Save the types to FILE, when needed. + +Should the variable `ctypes-write-types-at-exit' be nil this function +does nothing. Should it be the atom `ask' the user is prompted before +the types are saved. + +When FILE is nil, the variable `ctypes-file-name' is used." + (interactive) + (setq file (ctypes-gen-file-name file)) + (and (not ctypes-saved-p) + ctypes-write-types-at-exit + (or (not (eq ctypes-write-types-at-exit 'ask)) + (y-or-n-p (format "Save types in `%s'? " file))) + (ctypes-write-file file))) + + +(defun ctypes-interactive-read-file-name (prompt) + "Command argument reader, suitable for `interactive'." + (read-file-name prompt + default-directory + (file-name-nondirectory ctypes-file-name))) + + +(defun ctypes-gen-file-name (file) + "Generate the file name to used to read and write the types. + +Should FILE be nil or an empty string, the content of the +variable `ctypes-file-name' is used. Should FILE be a directory +name, the file part of `ctypes-file-name' is added to FILE." + (cond ((or (null file) (string= file "")) + ctypes-file-name) + ((file-directory-p file) + ;; I really would like a system-independent + ;; add-file-to-directory function... + (let* ((base (file-name-nondirectory ctypes-file-name)) + (first-try (concat file base))) + (if (string= base (file-name-nondirectory first-try)) + first-try + (concat file "/" base)))) + (t file))) + +;;}}} +;;{{{ Edit + +(defvar ctypes-edit-map nil + "Keymap used in ctypes-edit mode.") +(if ctypes-edit-map + nil + (setq ctypes-edit-map (make-sparse-keymap)) + (define-key ctypes-edit-map "\C-c\C-c" 'ctypes-edit-update-and-exit) + (define-key ctypes-edit-map "\C-c\C-x" 'ctypes-edit-update) + (define-key ctypes-edit-map "\C-c\C-w" 'ctypes-edit-write-file)) + + +(defvar ctypes-edit-types-for-mode nil + "Major mode that the edited types belong to. + +This is a buffer-local variable used by `ctypes-edit-mode'.") + + +(defun ctypes-edit (&optional mode) + "Create buffer for editing types in current major mode. + +The buffer can be edited using normal Emacs editing commands. When +done, press C-c C-c to use the edited version of the types. + +See also the function `ctypes-edit-types-in-mode'." + (interactive) + (or mode + (setq mode major-mode)) + (let ((buf (get-buffer-create "*ctypes-edit*")) + (lst (ctypes-get-types mode))) + (if (not (assq mode ctypes-mode-descriptor)) + (error "Can't edit types for %s %s" + mode "(see variable `ctypes-mode-descriptor').")) + (switch-to-buffer buf) + (set (make-local-variable 'ctypes-edit-types-for-mode) mode) + (erase-buffer) + (insert (format ";; Types for %s.\n" mode)) + (insert ";;\n") + (insert ";; Press `C-c C-c' to install types.\n") + (insert ";; `C-x k' to discard changes.\n\n") + (save-excursion + (dolist (type lst) + (insert type) + (insert "\n"))) + (set-buffer-modified-p nil) + (ctypes-edit-mode))) + + +;; This function is designed for interactive use only. +(defun ctypes-edit-types-in-mode (mode) + "Create buffer for editing types in major mode MODE. + +The buffer can be edited using normal Emacs editing commands. When +done, press C-c C-c to install the edited version of the types." + (interactive "sMode: ") + (ctypes-edit (ctypes-string-to-mode mode))) + + +(defun ctypes-edit-mode () + "Major mode for editing types. +\\{ctypes-edit-map}" + (interactive) + (setq major-mode 'ctypes-edit-mode) + (setq mode-name "CTypes-Edit") + (use-local-map ctypes-edit-map)) + + +(defun ctypes-edit-update (&optional delay-action) + "Install the types currently found in the *ctypes-edit* buffer. + +When preceded by C-u the display is not updated. + +Return non-nil if the set of types has been changed." + (interactive "P") + (if (not (eq major-mode 'ctypes-edit-mode)) + (error "Command only meaningful in the *ctypes-edit* buffer")) + (let* ((lst (ctypes-edit-get-types)) + (added (ctypes-set-types ctypes-edit-types-for-mode lst))) + (ctypes-perform-action ctypes-edit-types-for-mode added delay-action) + added)) + + +(defun ctypes-edit-update-and-exit (&optional inhibit-redraw) + "Install the types and close the edit buffer. + +When preceded by C-u the display is not updated. + +Return non-nil if the set of types has been changed." + (interactive "P") + (prog1 + (ctypes-edit-update inhibit-redraw) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer)))) + + +(defun ctypes-edit-write-file (file &optional inhibit-redraw) + (interactive + (list + (ctypes-interactive-read-file-name "Write types file: ") + current-prefix-arg)) + (ctypes-edit-update inhibit-redraw) + (ctypes-write-file file) + (set-buffer-modified-p nil)) + + +(defun ctypes-edit-get-types () + "Return, as a list of strings, the types in an `ctypes-edit' buffer. +The types could even be regexps." + (save-excursion + (let ((lst '())) + (goto-char (point-min)) + (while (< (point) (point-max)) + (skip-chars-forward " \t") + (if (not (eq (following-char) ?\;)) + (let ((p (point))) + (end-of-line) + (skip-chars-backward " \t") + (if (not (equal p (point))) + (setq lst (cons (buffer-substring-no-properties + p (point)) + lst))))) + (forward-line)) + (reverse lst)))) + +;;}}} +;;{{{ Types alist primitives + +;; This section contains functions that handle the actual set of types +;; found in each mode. + +(defvar ctypes-types-alist '() + "AList containing types for various modes. + +The car of each element is the major mode (a symbol) and the cdr is a +list containing the types (strings).") + + +(defun ctypes-get-types (mode) + "Return types for major mode MODE." + (let ((pair (assq mode ctypes-types-alist))) + (if pair + (cdr pair) + '()))) + + +(defun ctypes-set-types (mode type-list) + "Replace current set of types for major mode MODE. + +Return non-nil if the new set of types is different from the original set." + (let ((tmp '()) + (done nil) + added) + (while (not done) + (cond ((null ctypes-types-alist) + (setq added (not (null type-list))) + (setq done t)) + ((eq mode (car (car ctypes-types-alist))) + (setq added (not (ctypes-equal type-list + (cdr (car ctypes-types-alist))))) + (setq ctypes-types-alist (cdr ctypes-types-alist)) + (setq done t)) + (t + (setq tmp (cons (car ctypes-types-alist) tmp)) + (setq ctypes-types-alist (cdr ctypes-types-alist))))) + (if type-list + (setq ctypes-types-alist (cons (cons mode type-list) + ctypes-types-alist))) + (setq ctypes-types-alist (append (reverse tmp) ctypes-types-alist)) + (if added + (setq ctypes-saved-p nil)) + added)) + + +(defun ctypes-add-types (mode type-list) + "Add types in TYPE-LIST to major mode MODE. +Return non-nil if at least one new type was added." + (let ((current-types (ctypes-get-types mode)) + (added nil)) + (dolist (type (reverse type-list)) ; Try to keep original order. + (if (member type current-types) + () + (setq current-types (cons type current-types)) + (setq added t))) + (if added + (ctypes-set-types mode current-types)) + added)) + + +(defun ctypes-collect-types (mode) + "Return types for MODE, including inherited types." + (let ((modes (ctypes-collect-super-modes mode)) + (types '())) + (while modes + (setq types (ctypes-union-types types (ctypes-get-types (car modes)))) + (setq modes (cdr modes))) + types)) + + +(defun ctypes-collect-super-modes (mode) + "Return a list of all super modes to MODE. + +Note that we have not superimposed any type of structure on the +inheritance graph. For example, it can contain cycles! + +MODE is trivially a super mode to itself." + (let ((super-modes '()) + (must-check (list mode))) + (while must-check + (setq mode (car must-check)) + (setq must-check (cdr must-check)) + (let ((desc (assq mode ctypes-mode-descriptor))) + (cond (desc + (setq desc (cdr desc)) ;; Remove the mode name. + (while desc + (if (eq (nth 0 (car desc)) 'inherit) + (let ((other-mode (nth 1 (car desc)))) + (if (and (not (eq other-mode mode)) + (not (memq other-mode super-modes)) + (not (memq other-mode must-check))) + (setq must-check (cons other-mode must-check))))) + (setq desc (cdr desc))))) + (setq super-modes (cons mode super-modes)))) + super-modes)) + + +(defun ctypes-collect-sub-modes (mode) + "Return a list of all modes that inherits MODE." + (let ((sub-modes '()) + (alist ctypes-mode-descriptor)) + (while alist + (if (memq mode (ctypes-collect-super-modes (car (car alist)))) + (setq sub-modes (cons (car (car alist)) sub-modes))) + (setq alist (cdr alist))) + sub-modes)) + + +(defun ctypes-delete-types (mode type-list) + "Removes types in TYPE-LIST. +Return non-nil if any type was removed." + (let ((current-types (ctypes-get-types mode)) + (removed nil) + (new-list '())) + (while current-types + (if (member (car current-types) type-list) + (setq removed t) + (setq new-list (cons (car current-types) new-list))) + (setq current-types (cdr current-types))) + (if removed + (ctypes-set-types mode (reverse new-list))) + removed)) + + +;; Type-list primitives. + +(defun ctypes-equal (type-list1 type-list2) + "Non-nil if the lists contain the same types. +Note that the elements need not come in the same order in the two lists." + (and (ctypes-subset type-list1 type-list2) + (ctypes-subset type-list2 type-list1))) + + +(defun ctypes-subset (type-list1 type-list2) + "Non-nil if type-list1 is included in type-list2." + (let ((included t)) + (while (and included type-list1) + (if (not (member (car type-list1) type-list2)) + (setq included nil)) + (setq type-list1 (cdr type-list1))) + included)) + + +(defun ctypes-union-types (type-list1 type-list2) + "Return the union of the two type lists." + (setq type-list1 (reverse type-list1)) ; Try to maintain original order + (while type-list1 + (if (not (member (car type-list1) type-list2)) + (setq type-list2 (cons (car type-list1) type-list2))) + (setq type-list1 (cdr type-list1))) + type-list2) + +;;}}} +;;{{{ Perform Action + +(defvar ctypes-delayed-action-list '() + "List of major modes whose action has been delayed. + +Normally, this means that the user are executing a number of `ctypes' +and wants to wait to perform the display update until after the last +command. + +The actions are performed the next time the function +`ctypes-perform-action' is called with nil as it's DELAY-ACTION +argument, or when `ctypes-perform-delayed-action' is called.") + + +(defun ctypes-perform-action (modes changed-p delay-action) + "Perform action for all modes in MODES. + +MODES can a mode or a list of modes. + +The action is performed immediately for major modes in MODES, and for +major modes that inherits types from modes in MODES, when +`delay-action' is nil, and either changed-p is non-nil or the modes +previously have been marked for delayed action. + +Should DELAY-ACTION be non-nil, the actions are not performed +and the modes are marked for delayed action." + (if (not (listp modes)) + (setq modes (list modes))) + (cond (delay-action + ;; Mark all modes for delayed action. + (if changed-p + (while modes + (if (not (memq (car modes) ctypes-delayed-action-list)) + (setq ctypes-delayed-action-list + (cons (car modes) ctypes-delayed-action-list))) + (setq modes (cdr modes))))) + (t + ;; Unless a mode has been changed or has been aschedules for + ;; delayed action no action should be performed. + (if (not changed-p) + (let ((new-modes '())) + (while modes + (if (memq (car modes) ctypes-delayed-action-list) + (setq new-modes (cons (car modes) new-modes))) + (setq modes (cdr modes))) + (setq modes new-modes))) + ;; Update all modes that inherits types. + (let ((sub-modes '())) + (while modes + (let ((tmp (ctypes-collect-sub-modes (car modes)))) + (while tmp + (if (not (memq (car tmp) sub-modes)) + (setq sub-modes (cons (car tmp) sub-modes))) + (setq tmp (cdr tmp)))) + (setq modes (cdr modes))) + (setq modes sub-modes)) + ;; Remove all modes from the delayed action list: + (let ((new-modes modes) + (dlist (copy-sequence ctypes-delayed-action-list))) + ;; We make a copy of `ctypes-delayed-action-list' since we + ;; don't want to destructively a list that someone else + ;; might be using. A concrete example is when + ;; `ctypes-perform-delayed-action' is used; the variable + ;; `modes' is also bound to `ctypes-delayed-action-list'! + (while new-modes + (setq dlist (delq (car new-modes) dlist)) + (setq new-modes (cdr new-modes))) + (setq ctypes-delayed-action-list dlist)) + ;; Finally, perform the action. + (while modes + (let ((desc (assq (car modes) ctypes-mode-descriptor))) + (cond (desc + (setq desc (cdr desc)) ; Skip mode name + (while desc + (if (eq (nth 0 (car desc)) 'action) + (apply (nth 1 (car desc)) + (car modes) + (nthcdr 2 (car desc)))) + (setq desc (cdr desc)))))) + (setq modes (cdr modes)))))) + + +(defun ctypes-perform-delayed-action () + "Perform the action (normally update the display)" + (ctypes-perform-action ctypes-delayed-action-list nil nil)) + +;;}}} +;;{{{ The parser + +(defun ctypes-parse-buffer (&optional buffer mode filename) + "Parse BUFFER for types assuming the major mode MODE. + +Note: You can not assume the the buffer actually is in mode MODE. + +Note 2: The file name is only used for debugging." + (save-excursion + (if buffer + (set-buffer buffer)) + (or mode + (setq mode major-mode)) + (save-restriction + (widen) + (goto-char (point-min)) + (let ((desc (assq mode ctypes-mode-descriptor))) + (if desc + (let ((parser (assq 'parser desc))) + (if (null parser) + (error "No parser specified")) + (funcall (nth 1 parser) filename))))))) + + +(defun ctypes-parse-buffer-c (&optional filename) + "Return list of types found in current buffer." + (let ((orig-syntax-table (syntax-table))) + (require 'cc-mode) + (set-syntax-table c-mode-syntax-table) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (unwind-protect + (let ((lst '())) + (while (re-search-forward "^typedef\\>" nil t) + (condition-case () + (setq lst (append (ctypes-parse-typedef) lst)) + (error + (setq ctypes-parse-error + (list (or filename (buffer-file-name)) (point)))))) + lst) + (set-syntax-table orig-syntax-table)))) + + +;; TODO: classes need not start at the beginning of a line, do they? +(defun ctypes-parse-buffer-c++ (&optional filename) + "Return list of C++ types found in current buffer." + (let ((orig-syntax-table (syntax-table))) + (require 'cc-mode) + (set-syntax-table c-mode-syntax-table) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (unwind-protect + (let ((lst '())) + (while (re-search-forward "^\\(\\(typedef\\)\\|class\\)\\>" nil t) + (condition-case () + (if (match-beginning 2) + (setq lst (append (ctypes-parse-typedef) lst)) + (setq lst (cons (ctypes-parse-class) lst))) + (error + (setq ctypes-parse-error + (list (or filename (buffer-file-name)) (point)))))) + lst) + (set-syntax-table orig-syntax-table)))) + + +;; I'm not 100% convinced that I haven't oversimplified anything. +(defun ctypes-parse-typedef () + "Return the newly defined type in a typedef declaration. +Assume that the point is positioned directly after the `typedef'." + (ctypes-skip-blank) + ;; `const' can precede everything, including a `struct'. + (cond ((looking-at "\\") + (goto-char (match-end 0)) + (ctypes-skip-blank))) + ;; Skip past the basic type. + (cond ((looking-at ctypes-repetitive-type-regexp) + (goto-char (match-end 0)) + (ctypes-skip-blank) + (while (looking-at ctypes-repetitive-type-regexp) + (goto-char (match-end 0)) + (ctypes-skip-blank))) + ((looking-at "\\<\\(struct\\|union\\|enum\\)\\>") + (goto-char (match-end 0)) + (ctypes-skip-blank) + (if (looking-at ctypes-identifier-regexp) + (goto-char (match-end 0))) + (ctypes-skip-blank) + (if (eq (following-char) ?{) + (forward-sexp 1))) + ((eq (following-char) ?\() + ;; The basic type is complex, skip it. + (forward-sexp 1)) + ((looking-at ctypes-identifier-regexp) + ;; Another typedefed type? + (goto-char (match-end 0))) + (t + (error "Can't parse typedef statement"))) + (ctypes-skip-blank) + (while (memq (following-char) '(?& ?<)) + (cond ((eq (following-char) ?<) + ;; C++ template + (skip-chars-forward "^>") + (forward-char)) + ((eq (following-char) ?&) + ;; C++ Reference type + (forward-char))) + (ctypes-skip-blank)) + ;; Step into the type to find the name. Save the start position + ;; so we can pass over pairs of parentheses to find the next name. + (let ((types '())) + (while + (let (start) + (ctypes-skip-blank) + (setq start (point)) + (while (memq (following-char) '(?* ?\()) + (forward-char 1) + (ctypes-skip-blank)) + (cond ((looking-at ctypes-identifier-regexp) + (setq types (cons + (regexp-quote + (buffer-substring-no-properties + (match-beginning 0) (match-end 0))) + types))) + (t + (error "Parse error"))) + (goto-char start) + (while (looking-at + (concat "\\([*(&[]\\|\\(" ctypes-identifier-regexp + "\\)\\)")) + (cond ((match-beginning 2) + (goto-char (match-end 0))) + ((memq (following-char) '(?\( ?\[)) + (forward-sexp 1)) + (t + (forward-char))) + (ctypes-skip-blank)) + ;; Comment out this for a more liberal parser. + (if (not (memq (following-char) '(?, ?\;))) + (error "Parse Error")) + (eq (following-char) ?,)) + ;; I know it isn't much, but this is the body of the while-expression. + (forward-char)) + types)) + + +;; Probably wrong, since I don't speak C++. +(defun ctypes-parse-class () + (ctypes-skip-blank) + (if (looking-at ctypes-identifier-regexp) + (regexp-quote + (buffer-substring-no-properties (match-beginning 0) (match-end 0))) + (error "Not a valid class (I think)"))) + + +(defun ctypes-skip-blank (&optional lim) + (or lim (setq lim (point-max))) + (let ((stop nil)) + (while (and (not stop) (< (point) lim)) + (cond ((looking-at "//") + (skip-chars-forward "^\n" lim)) + ((looking-at "/\\*") + ;; A comment; there must be a better way to skip this. + (if (search-forward "*/" nil t) + (goto-char (match-end 0)) + (setq stop t))) + ((= (following-char) ?\n) + (skip-chars-forward "\n" lim)) + ((looking-at "^#") + (while (progn + (end-of-line) + (eq (preceding-char) ?\\)) + (forward-line)) + (forward-line)) + ((looking-at "\\s ") + (if (re-search-forward "\\S " lim 'move) + (forward-char -1))) + (t + (setq stop t)))) + stop)) + +;;}}} +;;{{{ TAGS + +(defun ctypes-tags-parse () + "Parse files in current TAGS table. Does not perform redraw. + +Return list of updated modes. + +See the function `ctypes-tags'." + (save-excursion + (let ((first-time t) + (modes '()) + new) + (while (condition-case () + (progn + (setq new (next-file first-time t)) + t) + (error nil)) + (setq first-time nil) + (let* ((buffer-file-name new) + (mode (or (and new (ctypes-get-mode)) major-mode))) + (if (assq mode ctypes-mode-descriptor) + (if (ctypes-buffer nil t mode) + (if (not (memq mode modes)) + (setq modes (cons mode modes))))))) + modes))) + +;;}}} +;;{{{ Major mode functions + +;; Sigh, all this code already exists in Emacs! However, In addition +;; to finding the mode that code also _activates_ the modes. Clearly, +;; this is not a Good Thing since we only would like to parse the +;; content and get on with it. +;; +;; Also, I had to chop up the original function `set-auto-mode' into +;; three parts since I needed to get access to the `auto-mode-alist' +;; code in isolation. + +(defun ctypes-get-mode (&optional buf) + "Return mode the buffer ought to have." + (or buf + (setq buf (current-buffer))) + (save-excursion + (set-buffer buf) + (or (let ((modes (ctypes-get-auto-mode buf))) + (cond ((eq modes '()) + nil) + ((= (length modes) 1) + (car modes)) + (t + ;; Several modes was specified using the -*- mode: + ;; foo; mode: bar; -*- construction. We have no idea + ;; which are major and which are minor modes so we + ;; pick the last one that is a member of + ;; `ctypes-mode-descriptor'. + (let ((done nil)) + (setq modes (reverse modes)) + (while (and (not done) (> (length modes) 1)) + (if (assq (car modes) ctypes-mode-descriptor) + (setq done t) + (setq modes (cdr modes)))) + (car modes))))) + (ctypes-get-mode-from-file-name) + (ctypes-get-mode-interpreter)))) + + +(defun ctypes-get-auto-mode (buf) + "Return list of modes specified in a -*- ... -*- header line." + (let (beg end modes) + (save-excursion + (goto-char (point-min)) + (skip-chars-forward " \t\n") + (and enable-local-variables + ;; Don't look for -*- if this file name matches any + ;; of the regexps in inhibit-first-line-modes-regexps. + (let ((temp inhibit-first-line-modes-regexps) + (name (if buffer-file-name + (file-name-sans-versions buffer-file-name) + (buffer-name)))) + (while (let ((sufs inhibit-first-line-modes-suffixes)) + (while (and sufs (not (string-match (car sufs) name))) + (setq sufs (cdr sufs))) + sufs) + (setq name (substring name 0 (match-beginning 0)))) + (while (and temp + (not (string-match (car temp) name))) + (setq temp (cdr temp))) + (not temp)) + (search-forward "-*-" (save-excursion + ;; If the file begins with "#!" + ;; (exec interpreter magic), look + ;; for mode frobs in the first two + ;; lines. You cannot necessarily + ;; put them in the first line of + ;; such a file without screwing up + ;; the interpreter invocation. + (end-of-line (and (looking-at "^#!") 2)) + (point)) t) + (progn + (skip-chars-forward " \t") + (setq beg (point)) + (search-forward "-*-" + (save-excursion (end-of-line) (point)) + t)) + (progn + (forward-char -3) + (skip-chars-backward " \t") + (setq end (point)) + (goto-char beg) + (if (save-excursion (search-forward ":" end t)) + ;; Find all specifications for the `mode:' variable + ;; and execute them left to right. + (while (let ((case-fold-search t)) + (or (and (looking-at "mode:") + (goto-char (match-end 0))) + (re-search-forward "[ \t;]mode:" end t))) + (skip-chars-forward " \t") + (setq beg (point)) + (if (search-forward ";" end t) + (forward-char -1) + (goto-char end)) + (skip-chars-backward " \t") + (setq modes + (cons (intern + (concat + (downcase + (buffer-substring beg (point))) "-mode")) + modes))) + ;; Simple -*-MODE-*- case. + (setq modes + (cons (intern + (concat (downcase (buffer-substring beg end)) + "-mode")) + modes)))))) + (reverse modes))) + + +(defun ctypes-get-mode-from-file-name (&optional name) + "Suggest major mode for file named NAME, no nil." + (or name + (setq name buffer-file-name)) + ;; Code taken from `set-auto-mode'. + (let ((keep-going t) + (mode nil)) + (setq name (file-name-sans-versions name)) + (while keep-going + (setq keep-going nil) + (let ((alist auto-mode-alist)) + ;; Find first matching alist entry. + (let ((case-fold-search (memq system-type '(vax-vms windows-nt)))) + (while (and (not mode) alist) + (if (string-match (car (car alist)) name) + (if (and (consp (cdr (car alist))) + (nth 2 (car alist))) + (setq mode (car (cdr (car alist))) + name (substring name 0 (match-beginning 0)) + keep-going t) + (setq mode (cdr (car alist)) + keep-going nil))) + (setq alist (cdr alist)))))) + mode)) + + +(defun ctypes-get-mode-interpreter () + "Get major mode based on #! sequence at head of buffer." + (save-excursion + (goto-char (point-min)) + (and (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)") + (cdr-safe (assoc (file-name-nondirectory + (buffer-substring (match-beginning 2) + (match-end 2))) + interpreter-mode-alist))))) + +;;}}} +;;{{{ Misc + +(or (fboundp 'font-lock-keyword-depth) + (defun font-lock-keyword-depth (keyword) + "Return the depth of KEYWORD regexp. +This means the number of parenthesized expressions." + (let ((count 0) start) + (while (string-match "\\\\(" keyword start) + (setq start (match-end 0) count (1+ count))) + count))) + + +(defun ctypes-string-to-mode (mode) + "Convert a mode name, entered by the user, to a mode symbol. + +Example: + (ctypes-string-to-mode \"C++\") => c++-mode" + (if (stringp mode) + (if (string-match "-mode$" mode) + (setq mode (intern mode)) + (setq mode (intern (concat mode "-mode"))))) + ;; Make sure "C++" works. + (if (not (assq mode ctypes-mode-descriptor)) + (let ((lowercase-mode (intern (downcase (symbol-name mode))))) + (if (assq lowercase-mode ctypes-mode-descriptor) + (setq mode lowercase-mode)))) + mode) + + +(defun ctypes-get-type-under-point () + (save-excursion + (if (eq (char-syntax (following-char)) ? ) + (skip-chars-backward " \t")) + (skip-chars-backward "a-zA-Z0-9:_$") + (and (looking-at ctypes-identifier-regexp) + (regexp-quote + (buffer-substring-no-properties + (match-beginning 0) + (match-end 0)))))) + +;;}}} +;;{{{ Font-lock stuff + +;; This section contains some font-lock support functions. +;; +;; Even though the main purpose of the `ctypes' package is to enhance +;; the fontification of C-like languages, the design of the package +;; does not limit itself to such narrow goal. Should you prefer to +;; use ctypes to anything else just redefine `ctypes-mode-descriptor'. + + +(defun ctypes-font-lock-set-extra-types (mode extra-types-var) + "Set a Emacs 19.35 (not yet released) style font-lock regexp." + (set extra-types-var (ctypes-get-types mode)) + (ctypes-font-lock-refontify mode)) + + +(defun ctypes-font-lock-refontify (mode) + "Refontify all buffers in major mode MODE." + (save-excursion + (let ((bufs (buffer-list))) + (while bufs + (set-buffer (car bufs)) + (if (and (eq major-mode mode) font-lock-mode) + (progn + (font-lock-mode -1) + (font-lock-mode 1))) + (setq bufs (cdr bufs)))))) + + +;; Pre Emacs 19.35 stuff below. + +(defvar ctypes-font-lock-keywords '() + "AList of all keywords installed by ctypes in font-lock keywords. + +This is needed when old keywords are replaced with newer.") + + +(defun ctypes-font-lock-add-keywords (mode rules) + "Add font-lock keywords for major mode MODE." + (let ((types (ctypes-get-types mode))) + (if (null types) + (ctypes-font-lock-delete-keywords mode rules) + (ctypes-font-lock-install-keywords + mode (mapconcat 'identity types "\\|") rules)) + (ctypes-font-lock-refontify mode))) + + +(defun ctypes-font-lock-install-keywords (mode regexp rules) + "Add REGEXP as new C-style types in major mode MODE. + +The rules is a list containing elements on the following form: + (number var [append]) + +Where `number' can be 1 or 2 and represents a simple and one complex +keyword, respectively. Normally, the simpler is defined at a lower +fontification but both are needed to get full fontification. + +`var' is the font-lock keyword variable to use and `append' is an +optional argument, when true the new keyword is appended to the end +of the keyword list." + (ctypes-font-lock-delete-keywords mode rules) + (let ((keyword-1 + (cons (concat "\\<\\(" regexp "\\)\\>") 'font-lock-type-face)) + (keyword-2 + (list + (concat "\\<\\(" regexp "\\)\\>\\([ \t*&]+\\sw+\\>\\)*") + ;; Fontify each declaration item. + (list 'font-lock-match-c++-style-declaration-item-and-skip-to-next + ;; Start with point after all type specifiers. + (list 'goto-char + (list 'or (list 'match-beginning + (+ 2 (font-lock-keyword-depth regexp))) + '(match-end 1))) + ;; Finish with point after first type specifier. + '(goto-char (match-end 1)) + ;; Fontify as a variable or function name. + '(1 (if (match-beginning 4) + font-lock-function-name-face + font-lock-variable-name-face)))))) + (setq ctypes-font-lock-keywords + (cons (list mode keyword-1 keyword-2) + ctypes-font-lock-keywords)) + (while rules + (let ((number (nth 0 (car rules))) + (var (nth 1 (car rules))) + (append-p (nth 2 (car rules))) + keywords) + (cond ((= number 1) + (setq keywords keyword-1)) + ((= number 2) + (setq keywords keyword-2)) + (t + (error "Incorrect entry in rule. Found `%s', expected 1 or 2." + number))) + (if append-p + (set var (append (symbol-value var) (list keywords))) + (set var (cons keywords (symbol-value var))))) + (setq rules (cdr rules))))) + + +(defun ctypes-font-lock-delete-keywords (mode rules) + "Delete keywords form major mode MODE, described by RULES. + +See the function `ctypes-font-lock-install-keywords' for a description +of RULES." + (let ((keywords (assq mode ctypes-font-lock-keywords))) + (if (null keywords) + () + (setq ctypes-font-lock-keywords + (delq keywords ctypes-font-lock-keywords)) + (setq keywords (cdr keywords)) ; Skip the mode name + (while rules + (let ((keywords keywords) ; Iteration-local alias + (var (nth 1 (car rules)))) + (while keywords + (set var (delq (car keywords) (symbol-value var))) + (setq keywords (cdr keywords)))) + (setq rules (cdr rules)))))) + +;;}}} + +;;{{{ Debug + +(defun ctypes-debug () + (interactive) + (with-output-to-temp-buffer "*CTypes-Debug*" + (princ "ctypes-types-alist:") + (print ctypes-types-alist) + (terpri) + + (princ "ctypes-font-lock-keywords:") + (print ctypes-font-lock-keywords) + (terpri) + + (princ "ctypes-delayed-action-list:") + (print ctypes-delayed-action-list) + (terpri))) + +;;}}} + +;; The End + +(add-hook 'find-file-hooks 'ctypes-find-file-hook) +(add-hook 'kill-emacs-hook 'ctypes-kill-emacs-hook) + +(provide 'ctypes) + +(run-hooks 'ctypes-load-hook) + +;; ctypes.el ends here. diff --git a/xemacs-packages/lisp/c-support/ctypes.elc b/xemacs-packages/lisp/c-support/ctypes.elc new file mode 100644 index 0000000000000000000000000000000000000000..c8172e394da158af7a3351a2d4cb70f9643a92c2 GIT binary patch literal 32444 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 Z2IzaU#c<4t?tYa0l?s1&U%`VS`wbNz4P*cS literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/hideif.el b/xemacs-packages/lisp/c-support/hideif.el new file mode 100644 index 00000000..94fb57fb --- /dev/null +++ b/xemacs-packages/lisp/c-support/hideif.el @@ -0,0 +1,1081 @@ +;;; hide-ifdef-mode.el --- hides selected code within ifdef. + +;; Copyright (C) 1988, 1994 Free Software Foundation, Inc. + +;; Author: Dan LaLiberte +;; Maintainer: FSF +;; Keywords: c, outlines + +;; This file is part of XEmacs. + +;; XEmacs 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. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Synched up with: FSF 20.4. + +;;; Commentary: + +;; To initialize, toggle the hide-ifdef minor mode with +;; +;; M-x hide-ifdef-mode +;; +;; This will set up key bindings and call hide-ifdef-mode-hook if it +;; has a value. To explicitly hide ifdefs using a buffer-local +;; define list (default empty), type +;; +;; M-x hide-ifdefs or C-c @ h +;; +;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't +;; pass through. The support of constant expressions in #if lines is +;; limited to identifiers, parens, and the operators: &&, ||, !, and +;; "defined". Please extend this. +;; +;; The hidden code is marked by ellipses (...). Be +;; cautious when editing near ellipses, since the hidden text is +;; still in the buffer, and you can move the point into it and modify +;; text unawares. If you don't want to see the ellipses, set +;; selective-display-ellipses to nil. But this can be dangerous. +;; You can make your buffer read-only while hide-ifdef-hiding by setting +;; hide-ifdef-read-only to a non-nil value. You can toggle this +;; variable with hide-ifdef-toggle-read-only (C-c @ C-q). +;; +;; You can undo the effect of hide-ifdefs by typing +;; +;; M-x show-ifdefs or C-c @ s +;; +;; Use M-x hide-ifdef-define (C-c @ d) to define a symbol. +;; Use M-x hide-ifdef-undef (C-c @ u) to undefine a symbol. +;; +;; If you define or undefine a symbol while hide-ifdef-mode is in effect, +;; the display will be updated. Only the define list for the current +;; buffer will be affected. You can save changes to the local define +;; list with hide-ifdef-set-define-alist. This adds entries +;; to hide-ifdef-define-alist. +;; +;; If you have defined a hide-ifdef-mode-hook, you can set +;; up a list of symbols that may be used by hide-ifdefs as in the +;; following example: +;; +;; (setq hide-ifdef-mode-hook +;; '(lambda () +;; (if (not hide-ifdef-define-alist) +;; (setq hide-ifdef-define-alist +;; '((list1 ONE TWO) +;; (list2 TWO THREE) +;; ))) +;; (hide-ifdef-use-define-alist 'list2) ; use list2 by default +;; )) +;; +;; You can call hide-ifdef-use-define-alist (C-c @ u) at any time to specify +;; another list to use. +;; +;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called, +;; set hide-ifdef-initially to non-nil. +;; +;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines. +;; In the absence of highlighting, that might be a bad idea. If you set +;; hide-ifdef-lines to nil (the default), the surrounding preprocessor +;; lines will be displayed. That can be confusing in its own +;; right. Other variations on display are possible, but not much +;; better. +;; +;; You can explicitly hide or show individual ifdef blocks irrespective +;; of the define list by using hide-ifdef-block and show-ifdef-block. +;; +;; You can move the point between ifdefs with forward-ifdef, backward-ifdef, +;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef. +;; +;; If you have minor-mode-alist in your mode line (the default) two labels +;; may appear. "Ifdef" will appear when hide-ifdef-mode is active. "Hiding" +;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil). +;; +;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL. +;; Extensively modified by Daniel LaLiberte (while at Gould). +;; +;; You may freely modify and distribute this, but keep a record +;; of modifications and send comments to: +;; liberte@a.cs.uiuc.edu or ihnp4!uiucdcs!liberte +;; I will continue to upgrade hide-ifdef-mode +;; with your contributions. + +;;; Code: + +(require 'cc-mode) + +(defgroup hide-ifdef nil + "Hide selected code within `ifdef'." + :group 'c) + +(defvar hide-ifdef-mode-submap nil + "Keymap used with Hide-Ifdef mode.") + +;;;###autoload +(defvar hide-ifdef-mode-map nil + "Keymap used with Hide-Ifdef mode.") + +;; XEmacs Change: Use vector notation. +(defconst hide-ifdef-mode-prefix-key [(control c) @] + "Prefix key for all Hide-Ifdef mode commands.") + +;; Set up the submap that goes after the prefix key. +(if hide-ifdef-mode-submap + () ; Don't redefine it. + (setq hide-ifdef-mode-submap (make-sparse-keymap)) + (define-key hide-ifdef-mode-submap "d" 'hide-ifdef-define) + (define-key hide-ifdef-mode-submap "u" 'hide-ifdef-undef) + (define-key hide-ifdef-mode-submap "D" 'hide-ifdef-set-define-alist) + (define-key hide-ifdef-mode-submap "U" 'hide-ifdef-use-define-alist) + + (define-key hide-ifdef-mode-submap "h" 'hide-ifdefs) + (define-key hide-ifdef-mode-submap "s" 'show-ifdefs) + (define-key hide-ifdef-mode-submap "\C-d" 'hide-ifdef-block) + (define-key hide-ifdef-mode-submap "\C-s" 'show-ifdef-block) + + (define-key hide-ifdef-mode-submap "\C-q" 'hide-ifdef-toggle-read-only) +;;(let ((where (where-is-internal 'toggle-read-only '(keymap) t))) +;; XEmacs change + (let ((where (where-is-internal 'toggle-read-only nil t))) + (if where + (define-key hide-ifdef-mode-submap + where + 'hide-ifdef-toggle-outside-read-only))) + ) + +;; Set up the mode's main map, which leads via the prefix key to the submap. +(if hide-ifdef-mode-map + () + (setq hide-ifdef-mode-map (make-sparse-keymap)) + (define-key hide-ifdef-mode-map hide-ifdef-mode-prefix-key + hide-ifdef-mode-submap)) + +(defvar hide-ifdef-mode nil + "Non-nil when hide-ifdef-mode is activated.") + +(defvar hide-ifdef-hiding nil + "Non-nil when text may be hidden.") + +(or (assq 'hide-ifdef-hiding minor-mode-alist) + (setq minor-mode-alist + (cons '(hide-ifdef-hiding " Hiding") + minor-mode-alist))) + +;(or (assq 'hide-ifdef-mode minor-mode-alist) +; (setq minor-mode-alist +; (cons '(hide-ifdef-mode " Ifdef") +; minor-mode-alist))) +;; XEmacs: do it right. +;;;###autoload +(add-minor-mode 'hide-ifdef-mode " Ifdef" hide-ifdef-mode-map) + +;; fix c-mode syntax table so we can recognize whole symbols. +(defvar hide-ifdef-syntax-table + (copy-syntax-table c-mode-syntax-table) + "Syntax table used for tokenizing #if expressions.") + +(modify-syntax-entry ?_ "w" hide-ifdef-syntax-table) +(modify-syntax-entry ?& "." hide-ifdef-syntax-table) +(modify-syntax-entry ?\| "." hide-ifdef-syntax-table) + +(defvar hide-ifdef-env nil + "An alist of defined symbols and their values.") + +(defvar hif-outside-read-only nil + "Internal variable. Saves the value of `buffer-read-only' while hiding.") + +;;;###autoload +(defun hide-ifdef-mode (arg) + "Toggle Hide-Ifdef mode. This is a minor mode, albeit a large one. +With ARG, turn Hide-Ifdef mode on if arg is positive, off otherwise. +In Hide-Ifdef mode, code within #ifdef constructs that the C preprocessor +would eliminate may be hidden from view. Several variables affect +how the hiding is done: + +hide-ifdef-env + An association list of defined and undefined symbols for the + current buffer. Initially, the global value of `hide-ifdef-env' + is used. + +hide-ifdef-define-alist + An association list of defined symbol lists. + Use `hide-ifdef-set-define-alist' to save the current `hide-ifdef-env' + and `hide-ifdef-use-define-alist' to set the current `hide-ifdef-env' + from one of the lists in `hide-ifdef-define-alist'. + +hide-ifdef-lines + Set to non-nil to not show #if, #ifdef, #ifndef, #else, and + #endif lines when hiding. + +hide-ifdef-initially + Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode + is activated. + +hide-ifdef-read-only + Set to non-nil if you want to make buffers read only while hiding. + After `show-ifdefs', read-only status is restored to previous value. + +\\{hide-ifdef-mode-map}" + + (interactive "P") + (make-local-variable 'hide-ifdef-mode) + (setq hide-ifdef-mode + (if (null arg) + (not hide-ifdef-mode) + (> (prefix-numeric-value arg) 0))) + + ;; XEmacs change + (redraw-modeline) + + (if hide-ifdef-mode + (progn + ; inherit global values + (make-local-variable 'hide-ifdef-env) + (setq hide-ifdef-env (default-value 'hide-ifdef-env)) + + (make-local-variable 'hide-ifdef-hiding) + (setq hide-ifdef-hiding (default-value 'hide-ifdef-hiding)) + + (make-local-variable 'hif-outside-read-only) + (setq hif-outside-read-only buffer-read-only) + + (run-hooks 'hide-ifdef-mode-hook) + + (if hide-ifdef-initially + (hide-ifdefs) + (show-ifdefs)) + (message "Enter Hide-Ifdef mode") + ) + ; else end hide-ifdef-mode + (if hide-ifdef-hiding + (show-ifdefs)) + (message "Exit Hide-Ifdef mode") + )) + + +;; from outline.el with docstring fixed. +(defun hif-outline-flag-region (from to flag) + "Hides or shows lines from FROM to TO, according to FLAG. +If FLAG is \\n (newline character) then text is shown, while if FLAG is \\^M +\(control-M) the text is hidden." + (let ((modp (buffer-modified-p))) + (unwind-protect (progn + (subst-char-in-region from to + (if (= flag ?\n) ?\^M ?\n) + flag t) ) + (set-buffer-modified-p modp)) + )) + +(defun hif-show-all () + "Show all of the text in the current buffer." + (interactive) + (hif-outline-flag-region (point-min) (point-max) ?\n)) + +;; By putting this on after-revert-hook, we arrange that it only +;; does anything when revert-buffer avoids turning off the mode. +;; (That can happen in VC.) +(defun hif-before-revert-function () + (and hide-ifdef-mode hide-ifdef-hiding + (hide-ifdefs t))) +(add-hook 'after-revert-hook 'hif-before-revert-function) + +(defun hide-ifdef-region (start end) + "START is the start of a #if or #else form. END is the ending part. +Everything including these lines is made invisible." + (hif-outline-flag-region start end ?\^M) + ) + +(defun hif-show-ifdef-region (start end) + "Everything between START and END is made visible." + (hif-outline-flag-region start end ?\n) + ) + + + +;===%%SF%% evaluation (Start) === + +;; It is not useful to set this to anything but `eval'. +;; In fact, the variable might as well be eliminated. +(defvar hide-ifdef-evaluator 'eval + "The function to use to evaluate a form. +The evaluator is given a canonical form and returns t if text under +that form should be displayed.") + +(defvar hif-undefined-symbol nil + "...is by default considered to be false.") + + +(defun hif-set-var (var value) + "Prepend (var value) pair to hide-ifdef-env." + (setq hide-ifdef-env (cons (cons var value) hide-ifdef-env))) + + +(defun hif-lookup (var) +; (message "hif-lookup %s" var) + (let ((val (assoc var hide-ifdef-env))) + (if val + (cdr val) + hif-undefined-symbol))) + +(defun hif-defined (var) + (hif-lookup var) + ; when #if expressions are fully supported, defined result should be 1 + ; (if (assoc var hide-ifdef-env) + ; 1 + ; nil) +) + + +;===%%SF%% evaluation (End) === + + + +;===%%SF%% parsing (Start) === +;;; The code that understands what ifs and ifdef in files look like. + +(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") +(defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef")) +(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+")) +(defconst hif-else-regexp (concat hif-cpp-prefix "else")) +(defconst hif-endif-regexp (concat hif-cpp-prefix "endif")) +(defconst hif-ifx-else-endif-regexp + (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp)) + +; Used to store the current token and the whole token list during parsing. +; Only bound dynamically. +(defvar hif-token) +(defvar hif-token-list) + +(defun hif-infix-to-prefix (token-list) + "Convert list of tokens in infix into prefix list" +; (message "hif-infix-to-prefix: %s" token-list) + (if (= 1 (length token-list)) + (` (hif-lookup (quote (, (car token-list))))) + (hif-parse-if-exp token-list)) + ) + +; pattern to match initial identifier, !, &&, ||, (, or ). +; Added ==, + and -: garyo@avs.com 8/9/94 +(defconst hif-token-regexp "^\\(&&\\|||\\|[!=]=\\|!\\|[()+-]\\|[<>]=?\\|\\w+\\)") +(defconst hif-end-of-comment "\\*/") + + +(defun hif-tokenize (expr-string) + "Separate string into a list of tokens" + (let ((token-list nil) + (expr-start 0) + (expr-length (length expr-string)) + (current-syntax-table (syntax-table))) + (unwind-protect + (progn + (set-syntax-table hide-ifdef-syntax-table) + (while (< expr-start expr-length) +; (message "expr-start = %d" expr-start) (sit-for 1) + (cond + ((string-match "^[ \t]+" expr-string expr-start) + ;; skip whitespace + (setq expr-start (match-end 0)) + ;; stick newline in string so ^ matches on the next string-match + (aset expr-string (1- expr-start) ?\n)) + + ((string-match "^/\\*" expr-string expr-start) + (setq expr-start (match-end 0)) + (aset expr-string (1- expr-start) ?\n) + (or + (string-match hif-end-of-comment + expr-string expr-start) ; eat comment + (string-match "$" expr-string expr-start)) ; multi-line comment + (setq expr-start (match-end 0)) + (aset expr-string (1- expr-start) ?\n)) + + ((string-match "^//" expr-string expr-start) + (string-match "$" expr-string expr-start) + (setq expr-start (match-end 0))) + + ((string-match hif-token-regexp expr-string expr-start) + (let ((token (substring expr-string expr-start (match-end 0)))) + (setq expr-start (match-end 0)) + (aset expr-string (1- expr-start) ?\n) +; (message "token: %s" token) (sit-for 1) + (setq token-list + (cons + (cond + ((string-equal token "||") 'or) + ((string-equal token "&&") 'and) + ((string-equal token "==") 'equal) + ((string-equal token "!=") 'hif-notequal) + ((string-equal token "!") 'not) + ((string-equal token "defined") 'hif-defined) + ((string-equal token "(") 'lparen) + ((string-equal token ")") 'rparen) + ((string-equal token ">") 'hif-greater) + ((string-equal token "<") 'hif-less) + ((string-equal token ">=") 'hif-greater-equal) + ((string-equal token "<=") 'hif-less-equal) + ((string-equal token "+") 'hif-plus) + ((string-equal token "-") 'hif-minus) + (t (intern token))) + token-list)))) + (t (error "Bad #if expression: %s" expr-string))))) + (set-syntax-table current-syntax-table)) + (nreverse token-list))) + +;;;----------------------------------------------------------------- +;;; Translate C preprocessor #if expressions using recursive descent. +;;; This parser is limited to the operators &&, ||, !, and "defined". +;;; Added ==, !=, +, and -. Gary Oberbrunner, garyo@avs.com, 8/9/94 + +(defun hif-parse-if-exp (hif-token-list) + "Parse the TOKEN-LIST. Return translated list in prefix form." + (hif-nexttoken) + (prog1 + (hif-expr) + (if hif-token ; is there still a token? + (error "Error: unexpected token: %s" hif-token)))) + +(defun hif-nexttoken () + "Pop the next token from token-list into the let variable \"hif-token\"." + (setq hif-token (car hif-token-list)) + (setq hif-token-list (cdr hif-token-list)) + hif-token) + +(defun hif-expr () + "Parse an expression as found in #if. + expr : term | expr '||' term." + (let ((result (hif-term))) + (while (eq hif-token 'or) + (hif-nexttoken) + (setq result (list 'or result (hif-term)))) + result)) + +(defun hif-term () + "Parse a term : eq-expr | term '&&' eq-expr." + (let ((result (hif-eq-expr))) + (while (eq hif-token 'and) + (hif-nexttoken) + (setq result (list 'and result (hif-eq-expr)))) + result)) + +(defun hif-eq-expr () + "Parse an eq-expr : math | eq-expr `=='|`!='|`<'|`>'|`>='|`<=' math." + (let ((result (hif-math)) + (eq-token nil)) + (while (memq hif-token '(equal hif-notequal hif-greater hif-less + hif-greater-equal hif-less-equal)) + (setq eq-token hif-token) + (hif-nexttoken) + (setq result (list eq-token result (hif-math)))) + result)) + +(defun hif-math () + "Parse an expression with + or - and simpler things. + math : factor | math '+|-' factor." + (let ((result (hif-factor)) + (math-op nil)) + (while (or (eq hif-token 'hif-plus) (eq hif-token 'hif-minus)) + (setq math-op hif-token) + (hif-nexttoken) + (setq result (list math-op result (hif-factor)))) + result)) + +(defun hif-factor () + "Parse a factor: '!' factor | '(' expr ')' | 'defined(' id ')' | id." + (cond + ((eq hif-token 'not) + (hif-nexttoken) + (list 'not (hif-factor))) + + ((eq hif-token 'lparen) + (hif-nexttoken) + (let ((result (hif-expr))) + (if (not (eq hif-token 'rparen)) + (error "Bad token in parenthesized expression: %s" hif-token) + (hif-nexttoken) + result))) + + ((eq hif-token 'hif-defined) + (hif-nexttoken) + (if (not (eq hif-token 'lparen)) + (error "Error: expected \"(\" after \"defined\"")) + (hif-nexttoken) + (let ((ident hif-token)) + (if (memq hif-token '(or and not hif-defined lparen rparen)) + (error "Error: unexpected token: %s" hif-token)) + (hif-nexttoken) + (if (not (eq hif-token 'rparen)) + (error "Error: expected \")\" after identifier")) + (hif-nexttoken) + (` (hif-defined (quote (, ident)))) + )) + + (t ; identifier + (let ((ident hif-token)) + (if (memq ident '(or and)) + (error "Error: missing identifier")) + (hif-nexttoken) + (` (hif-lookup (quote (, ident)))) + )) + )) + +(defun hif-mathify (val) + "Treat VAL as a number: if it's t or nil, use 1 or 0." + (cond ((eq val t) + 1) + ((null val) + 0) + (t val))) + +(defun hif-plus (a b) + "Like ordinary plus but treat t and nil as 1 and 0." + (+ (hif-mathify a) (hif-mathify b))) +(defun hif-minus (a b) + "Like ordinary minus but treat t and nil as 1 and 0." + (- (hif-mathify a) (hif-mathify b))) +(defun hif-notequal (a b) + "Like (not (equal A B)) but as one symbol." + (not (equal a b))) +(defun hif-greater (a b) + "Simple comparison." + (> (hif-mathify a) (hif-mathify b))) +(defun hif-less (a b) + "Simple comparison." + (< (hif-mathify a) (hif-mathify b))) +(defun hif-greater-equal (a b) + "Simple comparison." + (>= (hif-mathify a) (hif-mathify b))) +(defun hif-less-equal (a b) + "Simple comparison." + (<= (hif-mathify a) (hif-mathify b))) +;;;----------- end of parser ----------------------- + + +(defun hif-canonicalize () + "When at beginning of #ifX, returns a Lisp expression for its condition." + (save-excursion + (let ((negate (looking-at hif-ifndef-regexp))) + (re-search-forward hif-ifx-regexp) + (let* ((expr-string + (buffer-substring (point) + (progn (skip-chars-forward "^\n\r") (point)))) + (expr (hif-infix-to-prefix (hif-tokenize expr-string)))) +; (message "hif-canonicalized: %s" expr) + (if negate + (list 'not expr) + expr))))) + + +(defun hif-find-any-ifX () + "Move to next #if..., or #ifndef, at point or after." +; (message "find ifX at %d" (point)) + (prog1 + (re-search-forward hif-ifx-regexp (point-max) t) + (beginning-of-line))) + + +(defun hif-find-next-relevant () + "Move to next #if..., #else, or #endif, after the current line." +; (message "hif-find-next-relevant at %d" (point)) + (end-of-line) + ; avoid infinite recursion by only going to beginning of line if match found + (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t) + (beginning-of-line))) + +(defun hif-find-previous-relevant () + "Move to previous #if..., #else, or #endif, before the current line." +; (message "hif-find-previous-relevant at %d" (point)) + (beginning-of-line) + ; avoid infinite recursion by only going to beginning of line if match found + (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t) + (beginning-of-line))) + + +(defun hif-looking-at-ifX () ;; Should eventually see #if + (looking-at hif-ifx-regexp)) +(defun hif-looking-at-endif () + (looking-at hif-endif-regexp)) +(defun hif-looking-at-else () + (looking-at hif-else-regexp)) + + + +(defun hif-ifdef-to-endif () + "If positioned at #ifX or #else form, skip to corresponding #endif." +; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1) + (hif-find-next-relevant) + (cond ((hif-looking-at-ifX) + (hif-ifdef-to-endif) ; find endif of nested if + (hif-ifdef-to-endif)) ; find outer endif or else + ((hif-looking-at-else) + (hif-ifdef-to-endif)) ; find endif following else + ((hif-looking-at-endif) + 'done) + (t + (error "Mismatched #ifdef #endif pair")))) + + +(defun hif-endif-to-ifdef () + "If positioned at #endif form, skip backward to corresponding #ifX." +; (message "hif-endif-to-ifdef at %d" (point)) + (let ((start (point))) + (hif-find-previous-relevant) + (if (= start (point)) + (error "Mismatched #ifdef #endif pair"))) + (cond ((hif-looking-at-endif) + (hif-endif-to-ifdef) ; find beginning of nested if + (hif-endif-to-ifdef)) ; find beginning of outer if or else + ((hif-looking-at-else) + (hif-endif-to-ifdef)) + ((hif-looking-at-ifX) + 'done) + (t))) ; never gets here + + +(defun forward-ifdef (&optional arg) + "Move point to beginning of line of the next ifdef-endif. +With argument, do this that many times." + (interactive "p") + (or arg (setq arg 1)) + (if (< arg 0) + (backward-ifdef (- arg))) + (while (< 0 arg) + (setq arg (- arg)) + (let ((start (point))) + (if (not (hif-looking-at-ifX)) + (hif-find-next-relevant)) + (if (hif-looking-at-ifX) + (hif-ifdef-to-endif) + (goto-char start) + (error "No following #ifdef") + )))) + + +(defun backward-ifdef (&optional arg) + "Move point to beginning of the previous ifdef-endif. +With argument, do this that many times." + (interactive "p") + (or arg (setq arg 1)) + (if (< arg 0) + (forward-ifdef (- arg))) + (while (< 0 arg) + (setq arg (1- arg)) + (beginning-of-line) + (let ((start (point))) + (if (not (hif-looking-at-endif)) + (hif-find-previous-relevant)) + (if (hif-looking-at-endif) + (hif-endif-to-ifdef) + (goto-char start) + (error "No previous #ifdef"))))) + + +(defun down-ifdef () + "Move point to beginning of nested ifdef or else-part." + (interactive) + (let ((start (point))) + (hif-find-next-relevant) + (if (or (hif-looking-at-ifX) (hif-looking-at-else)) + () + (goto-char start) + (error "No following #ifdef")))) + + +(defun up-ifdef () + "Move point to beginning of enclosing ifdef or else-part." + (interactive) + (beginning-of-line) + (let ((start (point))) + (if (not (hif-looking-at-endif)) + (hif-find-previous-relevant)) + (if (hif-looking-at-endif) + (hif-endif-to-ifdef)) + (if (= start (point)) + (error "No previous #ifdef")))) + +(defun next-ifdef (&optional arg) + "Move to the beginning of the next #ifX, #else, or #endif. +With argument, do this that many times." + (interactive "p") + (or arg (setq arg 1)) + (if (< arg 0) + (previous-ifdef (- arg))) + (while (< 0 arg) + (setq arg (1- arg)) + (hif-find-next-relevant) + (if (eolp) + (progn + (beginning-of-line) + (error "No following #ifdefs, #elses, or #endifs"))))) + +(defun previous-ifdef (&optional arg) + "Move to the beginning of the previous #ifX, #else, or #endif. +With argument, do this that many times." + (interactive "p") + (or arg (setq arg 1)) + (if (< arg 0) + (next-ifdef (- arg))) + (while (< 0 arg) + (setq arg (1- arg)) + (let ((start (point))) + (hif-find-previous-relevant) + (if (= start (point)) + (error "No previous #ifdefs, #elses, or #endifs") + )))) + + +;===%%SF%% parsing (End) === + + +;===%%SF%% hide-ifdef-hiding (Start) === + + +;;; A range is a structure with four components: +;;; ELSE-P True if there was an else clause for the ifdef. +;;; START The start of the range. (beginning of line) +;;; ELSE The else marker (beginning of line) +;;; Only valid if ELSE-P is true. +;;; END The end of the range. (beginning of line) + +(defun hif-make-range (else-p start end &optional else) + (list else-p start else end)) + +(defun hif-range-else-p (range) (elt range 0)) +(defun hif-range-start (range) (elt range 1)) +(defun hif-range-else (range) (elt range 2)) +(defun hif-range-end (range) (elt range 3)) + + + +;;; Find-Range +;;; The workhorse, it delimits the #if region. Reasonably simple: +;;; Skip until an #else or #endif is found, remembering positions. If +;;; an #else was found, skip some more, looking for the true #endif. + +(defun hif-find-range () + "Returns a Range structure describing the current #if region. +Point is left unchanged." +; (message "hif-find-range at %d" (point)) + (save-excursion + (beginning-of-line) + (let ((start (point)) + (else-p nil) + (else nil) + (end nil)) + ;; Part one. Look for either #endif or #else. + ;; This loop-and-a-half dedicated to E. Dijkstra. + (hif-find-next-relevant) + (while (hif-looking-at-ifX) ; Skip nested ifdef + (hif-ifdef-to-endif) + (hif-find-next-relevant)) + ;; Found either a #else or an #endif. + (cond ((hif-looking-at-else) + (setq else-p t) + (setq else (point))) + (t + (setq end (point)) ; (save-excursion (end-of-line) (point)) + )) + ;; If found #else, look for #endif. + (if else-p + (progn + (hif-find-next-relevant) + (while (hif-looking-at-ifX) ; Skip nested ifdef + (hif-ifdef-to-endif) + (hif-find-next-relevant)) + (if (hif-looking-at-else) + (error "Found two elses in a row? Broken!")) + (setq end (point)) ; (save-excursion (end-of-line) (point)) + )) + (hif-make-range else-p start end else)))) + + +;;; A bit slimy. +;;; NOTE: If there's an #ifdef at the beginning of the file, we can't +;;; hide it. There's no previous newline to replace. If we added +;;; one, we'd throw off all the counts. Feh. + +(defun hif-hide-line (point) + "Hide the line containing point. Does nothing if `hide-ifdef-lines' is nil." + (if hide-ifdef-lines + (save-excursion + (goto-char point) + (let ((modp (buffer-modified-p))) + (unwind-protect + (progn + (beginning-of-line) + (if (not (= (point) 1)) + (hide-ifdef-region (1- (point)) (point)))) + (set-buffer-modified-p modp)) + )) + )) + + +;;; Hif-Possibly-Hide +;;; There are four cases. The #ifX expression is "taken" if it +;;; the hide-ifdef-evaluator returns T. Presumably, this means the code +;;; inside the #ifdef would be included when the program was +;;; compiled. +;;; +;;; Case 1: #ifX taken, and there's an #else. +;;; The #else part must be hidden. The #if (then) part must be +;;; processed for nested #ifX's. +;;; Case 2: #ifX taken, and there's no #else. +;;; The #if part must be processed for nested #ifX's. +;;; Case 3: #ifX not taken, and there's an #else. +;;; The #if part must be hidden. The #else part must be processed +;;; for nested #ifs. +;;; Case 4: #ifX not taken, and there's no #else. +;;; The #ifX part must be hidden. +;;; +;;; Further processing is done by narrowing to the relevant region +;;; and just recursively calling hide-ifdef-guts. +;;; +;;; When hif-possibly-hide returns, point is at the end of the +;;; possibly-hidden range. + +(defun hif-recurse-on (start end) + "Call `hide-ifdef-guts' after narrowing to end of START line and END line." + (save-excursion + (save-restriction + (goto-char start) + (end-of-line) + (narrow-to-region (point) end) + (hide-ifdef-guts)))) + +(defun hif-possibly-hide () + "Called at #ifX expression, this hides those parts that should be hidden. +It uses the judgment of `hide-ifdef-evaluator'." +; (message "hif-possibly-hide") (sit-for 1) + (let ((test (hif-canonicalize)) + (range (hif-find-range))) +; (message "test = %s" test) (sit-for 1) + + (hif-hide-line (hif-range-end range)) + (if (funcall hide-ifdef-evaluator test) + (cond ((hif-range-else-p range) ; case 1 + (hif-hide-line (hif-range-else range)) + (hide-ifdef-region (hif-range-else range) + (1- (hif-range-end range))) + (hif-recurse-on (hif-range-start range) + (hif-range-else range))) + (t ; case 2 + (hif-recurse-on (hif-range-start range) + (hif-range-end range)))) + (cond ((hif-range-else-p range) ; case 3 + (hif-hide-line (hif-range-else range)) + (hide-ifdef-region (hif-range-start range) + (1- (hif-range-else range))) + (hif-recurse-on (hif-range-else range) + (hif-range-end range))) + (t ; case 4 + (hide-ifdef-region (point) + (1- (hif-range-end range)))) + )) + (hif-hide-line (hif-range-start range)) ; Always hide start. + (goto-char (hif-range-end range)) + (end-of-line) + )) + + + +(defun hide-ifdef-guts () + "Does most of the work of `hide-ifdefs'. +It does not do the work that's pointless to redo on a recursive entry." +; (message "hide-ifdef-guts") + (save-excursion + (goto-char (point-min)) + (while (hif-find-any-ifX) + (hif-possibly-hide)))) + +;===%%SF%% hide-ifdef-hiding (End) === + + +;===%%SF%% exports (Start) === + +;;;###autoload +(defcustom hide-ifdef-initially nil + "*Non-nil means call `hide-ifdefs' when Hide-Ifdef mode is first activated." + :type 'boolean + :group 'hide-ifdef) + +;;;###autoload +(defcustom hide-ifdef-read-only nil + "*Set to non-nil if you want buffer to be read-only while hiding text." + :type 'boolean + :group 'hide-ifdef) + +;;;###autoload +(defcustom hide-ifdef-lines nil + "*Non-nil means hide the #ifX, #else, and #endif lines." + :type 'boolean + :group 'hide-ifdef) + +(defun hide-ifdef-toggle-read-only () + "Toggle hide-ifdef-read-only." + (interactive) + (setq hide-ifdef-read-only (not hide-ifdef-read-only)) + (message "Hide-Read-Only %s" + (if hide-ifdef-read-only "ON" "OFF")) + (if hide-ifdef-hiding + (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) + ;; XEmacs change + (redraw-modeline)) + +(defun hide-ifdef-toggle-outside-read-only () + "Replacement for `toggle-read-only' within Hide-Ifdef mode." + (interactive) + (setq hif-outside-read-only (not hif-outside-read-only)) + (message "Read only %s" + (if hif-outside-read-only "ON" "OFF")) + (setq buffer-read-only + (or (and hide-ifdef-hiding hide-ifdef-read-only) + hif-outside-read-only) + ) + ;; XEmacs change + (redraw-modeline)) + + +(defun hide-ifdef-define (var) + "Define a VAR so that #ifdef VAR would be included." + (interactive "SDefine what? ") + (hif-set-var var 1) + (if hide-ifdef-hiding (hide-ifdefs))) + +(defun hide-ifdef-undef (var) + "Undefine a VAR so that #ifdef VAR would not be included." + (interactive "SUndefine what? ") + (hif-set-var var nil) + (if hide-ifdef-hiding (hide-ifdefs))) + + +(defun hide-ifdefs (&optional nomsg) + "Hide the contents of some #ifdefs. +Assume that defined symbols have been added to `hide-ifdef-env'. +The text hidden is the text that would not be included by the C +preprocessor if it were given the file with those symbols defined. + +Turn off hiding by calling `show-ifdefs'." + + (interactive) + (message "Hiding...") + (setq hif-outside-read-only buffer-read-only) + (if (not hide-ifdef-mode) + (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode + (if hide-ifdef-hiding + (show-ifdefs)) ; Otherwise, deep confusion. + (let ((inhibit-read-only t)) + (setq selective-display t) + (setq hide-ifdef-hiding t) + (hide-ifdef-guts)) + (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)) + (or nomsg + (message "Hiding done"))) + + +(defun show-ifdefs () + "Cancel the effects of `hide-ifdef': show the contents of all #ifdefs." + (interactive) + (setq buffer-read-only hif-outside-read-only) + (setq selective-display nil) ; defaults + (let ((inhibit-read-only t)) + (hif-show-all)) + (setq hide-ifdef-hiding nil)) + + +(defun hif-find-ifdef-block () + "Utility for hide and show `ifdef-block'. +Return as (TOP . BOTTOM) the extent of ifdef block." + (let (max-bottom) + (cons (save-excursion + (beginning-of-line) + (if (not (or (hif-looking-at-else) (hif-looking-at-ifX))) + (up-ifdef)) + (prog1 (point) + (hif-ifdef-to-endif) + (setq max-bottom (1- (point))))) + (save-excursion + (beginning-of-line) + (if (not (hif-looking-at-endif)) + (hif-find-next-relevant)) + (while (hif-looking-at-ifX) + (hif-ifdef-to-endif) + (hif-find-next-relevant)) + (min max-bottom (1- (point))))))) + + +(defun hide-ifdef-block () + "Hide the ifdef block (true or false part) enclosing or before the cursor." + (interactive) + (if (not hide-ifdef-mode) + (hide-ifdef-mode 1)) + (setq selective-display t) + (let ((top-bottom (hif-find-ifdef-block)) + (inhibit-read-only t)) + (hide-ifdef-region (car top-bottom) (cdr top-bottom)) + (if hide-ifdef-lines + (progn + (hif-hide-line (car top-bottom)) + (hif-hide-line (1+ (cdr top-bottom))))) + (setq hide-ifdef-hiding t)) + (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) + + +(defun show-ifdef-block () + "Show the ifdef block (true or false part) enclosing or before the cursor." + (interactive) + (let ((inhibit-read-only t)) + (if hide-ifdef-lines + (save-excursion + (beginning-of-line) + (hif-show-ifdef-region (1- (point)) (progn (end-of-line) (point)))) + + (let ((top-bottom (hif-find-ifdef-block))) + (hif-show-ifdef-region (1- (car top-bottom)) (cdr top-bottom)))))) + + +;;; definition alist support + +(defvar hide-ifdef-define-alist nil + "A global assoc list of pre-defined symbol lists") + +(defun hif-compress-define-list (env) + "Compress the define list ENV into a list of defined symbols only." + (let ((defs (mapcar '(lambda (arg) + (if (hif-lookup (car arg)) (car arg))) + env)) + (new-defs nil)) + (while defs + (if (car defs) + (setq new-defs (cons (car defs) new-defs))) + (setq defs (cdr defs))) + new-defs)) + +(defun hide-ifdef-set-define-alist (name) + "Set the association for NAME to `hide-ifdef-env'." + (interactive "SSet define list: ") + (setq hide-ifdef-define-alist + (cons (cons name (hif-compress-define-list hide-ifdef-env)) + hide-ifdef-define-alist))) + +(defun hide-ifdef-use-define-alist (name) + "Set `hide-ifdef-env' to the define list specified by NAME." + (interactive "SUse define list: ") + (let ((define-list (assoc name hide-ifdef-define-alist))) + (if define-list + (setq hide-ifdef-env + (mapcar '(lambda (arg) (cons arg t)) + (cdr define-list))) + (error "No define list for %s" name)) + (if hide-ifdef-hiding (hide-ifdefs)))) + +(provide 'hideif) + +;;; hideif.el ends here diff --git a/xemacs-packages/lisp/c-support/hideif.elc b/xemacs-packages/lisp/c-support/hideif.elc new file mode 100644 index 0000000000000000000000000000000000000000..94a7907fb7dce66bd674861e9d610e9ae2d2c4f3 GIT binary patch literal 19469 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 Q;5A+%tHEKuQA&3FKYcytZ~y=R literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/c-support/hideshow.el b/xemacs-packages/lisp/c-support/hideshow.el new file mode 100644 index 00000000..e3f6745c --- /dev/null +++ b/xemacs-packages/lisp/c-support/hideshow.el @@ -0,0 +1,933 @@ +;;; hideshow.el --- minor mode cmds to selectively display code/comment blocks + +;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01 Free Software Foundation + +;; Author: Thien-Thi Nguyen +;; Dan Nicolaescu +;; Keywords: C C++ java lisp tools editing comments blocks hiding outlines +;; Maintainer-Version: 5.31 +;; Time-of-Day-Author-Most-Likely-to-be-Recalcitrant: early morning +;; +;; XEmacs port by Jerry James +;; This port consists almost entirely of substituting extent manipulations for +;; overlay manipulations. + +;; This file is part of XEmacs. + +;; XEmacs 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. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; * Commands provided +;; +;; This file provides Hideshow Minor Mode. When active, nine commands +;; are available, implementing block hiding and showing. They (and their +;; keybindings) are: +;; +;; hs-hide-block C-c @ C-h +;; hs-show-block C-c @ C-s +;; hs-hide-all C-c @ C-M-h +;; hs-show-all C-c @ C-M-s +;; hs-hide-level C-c @ C-l +;; hs-toggle-hiding C-c @ C-c +;; hs-mouse-toggle-hiding [(shift mouse-2)] +;; hs-hide-initial-comment-block +;; +;; Blocks are defined per mode. In c-mode, c++-mode and java-mode, they +;; are simply text between curly braces, while in Lisp-ish modes parens +;; are used. Multi-line comment blocks can also be hidden. Read-only +;; buffers are not a problem, since hideshow doesn't modify the text. +;; +;; The command `M-x hs-minor-mode' toggles the minor mode or sets it +;; (similar to other minor modes). + +;; * Suggested usage +;; +;; First make sure hideshow.el is in a directory in your `load-path'. +;; You can optionally byte-compile it using `M-x byte-compile-file'. +;; Then, add the following to your ~/.emacs: +;; +;; (load-library "hideshow") +;; (add-hook 'X-mode-hook ; other modes similarly +;; '(lambda () (hs-minor-mode 1))) +;; +;; where X = {emacs-lisp,c,c++,perl,...}. You can also manually toggle +;; hideshow minor mode by typing `M-x hs-minor-mode'. After hideshow is +;; activated or deactivated, `hs-minor-mode-hook' is run w/ `run-hooks'. +;; +;; Additionally, Joseph Eydelnant writes: +;; I enjoy your package hideshow.el Ver. 5.24 2001/02/13 +;; a lot and I've been looking for the following functionality: +;; toggle hide/show all with a single key. +;; Here are a few lines of code that lets me do just that. +;; +;; (defvar my-hs-hide nil "Current state of hideshow for toggling all.") +;; ;;;###autoload +;; (defun my-toggle-hideshow-all () "Toggle hideshow all." +;; (interactive) +;; (setq my-hs-hide (not my-hs-hide)) +;; (if my-hs-hide +;; (hs-hide-all) +;; (hs-show-all))) +;; +;; [Your hideshow hacks here!] + +;; * Customization +;; +;; You can use `M-x customize-variable' on the following variables: +;; +;; - hs-hide-comments-when-hiding-all -- self-explanatory! +;; - hs-hide-all-non-comment-function -- if non-nil, when doing a +;; `hs-hide-all', this function +;; is called w/ no arguments +;; - hs-isearch-open -- what kind of hidden blocks to +;; open when doing isearch +;; +;; Some languages (e.g., Java) are deeply nested, so the normal behavior +;; of `hs-hide-all' (hiding all but top-level blocks) results in very +;; little information shown, which is not very useful. You can use the +;; variable `hs-hide-all-non-comment-function' to implement your idea of +;; what is more useful. For example, the following code shows the next +;; nested level in addition to the top-level: +;; +;; (defun ttn-hs-hide-level-1 () +;; (hs-hide-level 1) +;; (forward-sexp 1)) +;; (setq hs-hide-all-non-comment-function 'ttn-hs-hide-level-1) +;; +;; Hideshow works w/ incremental search (isearch) by setting the variable +;; `hs-headline', which is the line of text at the beginning of a hidden +;; block that contains a match for the search. You can have this show up +;; in the mode line by modifying the variable `mode-line-format'. For +;; example, the following code prepends this info to the mode line: +;; +;; (unless (memq 'hs-headline mode-line-format) +;; (setq mode-line-format +;; (append '("-" hs-headline) mode-line-format))) +;; +;; See documentation for `mode-line-format' for more info. +;; +;; Hooks are run after some commands: +;; +;; hs-hide-hook in hs-hide-block, hs-hide-all, hs-hide-level +;; hs-show-hook hs-show-block, hs-show-all +;; +;; One of `hs-hide-hook' or `hs-show-hook' is run for the toggling +;; commands when the result of the toggle is to hide or show blocks, +;; respectively. All hooks are run w/ `run-hooks'. See docs for each +;; variable or hook for more info. +;; +;; Normally, hideshow tries to determine appropriate values for block +;; and comment definitions by examining the buffer's major mode. If +;; there are problems, hideshow will not activate and in that case you +;; may wish to override hideshow's heuristics by adding an entry to +;; variable `hs-special-modes-alist'. Packages that use hideshow should +;; do something like: +;; +;; (let ((my-mode-hs-info '(my-mode "{{" "}}" ...))) +;; (if (not (member my-mode-hs-info hs-special-modes-alist)) +;; (setq hs-special-modes-alist +;; (cons my-mode-hs-info hs-special-modes-alist)))) +;; +;; If you have an entry that works particularly well, consider +;; submitting it for inclusion in hideshow.el. See docstring for +;; `hs-special-modes-alist' for more info on the entry format. + +;; * Bugs +;; +;; (1) Hideshow does not work w/ emacs 18 because emacs 18 lacks the +;; function `forward-comment' (among other things). If someone +;; writes this, please send me a copy. +;; +;; (2) Sometimes `hs-headline' can become out of sync. To reset, type +;; `M-x hs-minor-mode' twice (that is, deactivate then re-activate +;; hideshow). +;; +;; (3) Hideshow 5.x is developed and tested on GNU Emacs 20.7. +;; XEmacs compatibility may have bitrotted since 4.29. +;; [Jerry says: XEmacs compatibility is back! Give it a try.] +;; +;; (4) Some buffers can't be `byte-compile-file'd properly. This is because +;; `byte-compile-file' inserts the file to be compiled in a temporary +;; buffer and switches `normal-mode' on. In the case where you have +;; `hs-hide-initial-comment-block' in `hs-minor-mode-hook', the hiding of +;; the initial comment sometimes hides parts of the first statement (seems +;; to be only in `normal-mode'), so there are unbalanced "(" and ")". +;; +;; The workaround is to clear `hs-minor-mode-hook' when byte-compiling: +;; +;; (defadvice byte-compile-file (around +;; byte-compile-file-hideshow-off +;; act) +;; (let ((hs-minor-mode-hook nil)) +;; ad-do-it)) +;; +;; (5) Hideshow interacts badly with Ediff and `vc-diff'. At the moment, the +;; suggested workaround is to turn off hideshow entirely, for example: +;; +;; (defun turn-off-hideshow () (hs-minor-mode -1)) +;; (add-hook 'ediff-prepare-buffer-hook 'turn-off-hideshow) +;; (add-hook 'vc-before-checkin-hook 'turn-off-hideshow) +;; +;; In the case of `vc-diff', here is a less invasive workaround: +;; +;; (add-hook 'vc-before-checkin-hook +;; '(lambda () +;; (goto-char (point-min)) +;; (hs-show-block))) +;; +;; Unfortunately, these workarounds do not restore hideshow state. +;; If someone figures out a better way, please let me know. + +;; * Correspondance +;; +;; Correspondance welcome; please indicate version number. Send bug +;; reports and inquiries to . +;; If the bug appears to be XEmacs-specific, use M-x report-emacs-bug instead. + +;; * Thanks +;; +;; Thanks go to the following people for valuable ideas, code and +;; bug reports. +;; +;; Dean Andrews, Alf-Ivar Holm, Holger Bauer, Christoph Conrad, Dave +;; Love, Dirk Herrmann, Gael Marziou, Jan Djarv, Guillaume Leray, +;; Moody Ahmad, Preston F. Crow, Lars Lindberg, Reto Zimmermann, +;; Keith Sheffield, Chew Meng Kuan, Tony Lam, Pete Ware, François +;; Pinard, Stefan Monnier, Joseph Eydelnant +;; +;; Special thanks go to Dan Nicolaescu, who reimplemented hideshow using +;; overlays (rather than selective display), added isearch magic, folded +;; in custom.el compatibility, generalized comment handling, incorporated +;; mouse support, and maintained the code in general. Version 4.0 is +;; largely due to his efforts. + +;; * History +;; +;; Hideshow was inspired when I learned about selective display. It was +;; reimplemented to use overlays for 4.0 (see above). WRT older history, +;; entries in the masterfile corresponding to versions 1.x and 2.x have +;; been lost. XEmacs support is reliable as of 4.29. State save and +;; restore was added in 3.5 (not widely distributed), and reliable as of +;; 4.30. Otherwise, the code seems stable. Passes checkdoc as of 4.32. +;; Version 5.x uses new algorithms for block selection and traversal, +;; unbundles state save and restore, and includes more isearch support. + +;;; Code: + +(require 'easymenu) + +;;--------------------------------------------------------------------------- +;; user-configurable variables + +(defgroup hideshow nil + "Minor mode for hiding and showing program and comment blocks." + :prefix "hs-" + :group 'languages) + +;;;###autoload +(defcustom hs-hide-comments-when-hiding-all t + "*Hide the comments too when you do an `hs-hide-all'." + :type 'boolean + :group 'hideshow) + +(defcustom hs-minor-mode-hook nil + "*Hook called when hideshow minor mode is activated or deactivated." + :type 'hook + :group 'hideshow + :version "21.1") + +(defcustom hs-isearch-open 'code + "*What kind of hidden blocks to open when doing `isearch'. +One of the following symbols: + + code -- open only code blocks + comment -- open only comment blocks + t -- open both code and comment blocks + nil -- open neither code nor comment blocks + +This has effect iff `search-invisible' is set to `open'." + :type '(choice (const :tag "open only code blocks" code) + (const :tag "open only comment blocks" comment) + (const :tag "open both code and comment blocks" t) + (const :tag "don't open any of them" nil)) + :group 'hideshow) + +;;;###autoload +(defvar hs-special-modes-alist + '((c-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning) + (c++-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning) + (bibtex-mode ("^@\\S(*\\(\\s(\\)" 1)) + (java-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning) + ) + "*Alist for initializing the hideshow variables for different modes. +Each element has the form + (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC). + +If non-nil, hideshow will use these values as regexps to define blocks +and comments, respectively for major mode MODE. + +START, END and COMMENT-START are regular expressions. A block is +defined as text surrounded by START and END. + +As a special case, START may be a list of the form (COMPLEX-START +MDATA-SELECTOR), where COMPLEX-START is a regexp w/ multiple parts and +MDATA-SELECTOR an integer that specifies which sub-match is the proper +place to adjust point, before calling `hs-forward-sexp-func'. For +example, see the `hs-special-modes-alist' entry for `bibtex-mode'. + +For some major modes, `forward-sexp' does not work properly. In those +cases, FORWARD-SEXP-FUNC specifies another function to use instead. + +See the documentation for `hs-adjust-block-beginning' to see what is the +use of ADJUST-BEG-FUNC. + +If any of the elements is left nil or omitted, hideshow tries to guess +appropriate values. The regexps should not contain leading or trailing +whitespace. Case does not matter.") + +(defvar hs-hide-all-non-comment-function nil + "*Function called if non-nil when doing `hs-hide-all' for non-comments.") + +(defvar hs-hide-hook nil + "*Hook called (with `run-hooks') at the end of commands to hide text. +These commands include the toggling commands (when the result is to hide +a block), `hs-hide-all', `hs-hide-block' and `hs-hide-level'.") + +(defvar hs-show-hook nil + "*Hook called (with `run-hooks') at the end of commands to show text. +These commands include the toggling commands (when the result is to show +a block), `hs-show-all' and `hs-show-block'..") + +;;--------------------------------------------------------------------------- +;; internal variables + +(defvar hs-minor-mode nil + "Non-nil if using hideshow mode as a minor mode of some other mode. +Use the command `hs-minor-mode' to toggle or set this variable.") + +(defvar hs-minor-mode-map nil + "Keymap for hideshow minor mode.") + +(defvar hs-minor-mode-menu nil + "Menu for hideshow minor mode.") + +(defvar hs-c-start-regexp nil + "Regexp for beginning of comments. +Differs from mode-specific comment regexps in that +surrounding whitespace is stripped.") + +(defvar hs-block-start-regexp nil + "Regexp for beginning of block.") + +(defvar hs-block-start-mdata-select nil + "Element in `hs-block-start-regexp' match data to consider as block start. +The internal function `hs-forward-sexp' moves point to the beginning of this +element (using `match-beginning') before calling `hs-forward-sexp-func'.") + +(defvar hs-block-end-regexp nil + "Regexp for end of block.") + +(defvar hs-forward-sexp-func 'forward-sexp + "Function used to do a `forward-sexp'. +Should change for Algol-ish modes. For single-character block +delimiters -- ie, the syntax table regexp for the character is +either `(' or `)' -- `hs-forward-sexp-func' would just be +`forward-sexp'. For other modes such as simula, a more specialized +function is necessary.") + +(defvar hs-adjust-block-beginning nil + "Function used to tweak the block beginning. +The block is hidden from the position returned by this function, +as opposed to hiding it from the position returned when searching +for `hs-block-start-regexp'. + +For example, in c-like modes, if we wish to also hide the curly braces +(if you think they occupy too much space on the screen), this function +should return the starting point (at the end of line) of the hidden +region. + +It is called with a single argument ARG which is the the position in +buffer after the block beginning. + +It should return the position from where we should start hiding. + +It should not move the point. + +See `hs-c-like-adjust-block-beginning' for an example of using this.") + +(defvar hs-headline nil + "Text of the line where a hidden block begins, set during isearch. +You can display this in the mode line by adding the symbol `hs-headline' +to the variable `mode-line-format'. For example, + + (unless (memq 'hs-headline mode-line-format) + (setq mode-line-format + (append '(\"-\" hs-headline) mode-line-format))) + +Note that `mode-line-format' is buffer-local.") + +;;--------------------------------------------------------------------------- +;; system dependency + +;; XEmacs and emacs-19 compatibility +(if (not (fboundp 'add-to-invisibility-spec)) + (defun add-to-invisibility-spec (arg) + "Add elements to `buffer-invisibility-spec'. +See documentation for `buffer-invisibility-spec' for the kind of elements +that can be added." + (if (eq buffer-invisibility-spec t) + (setq buffer-invisibility-spec (list t))) + (setq buffer-invisibility-spec + (cons arg buffer-invisibility-spec)))) + +(if (not (fboundp 'remove-from-invisibility-spec)) + (defun remove-from-invisibility-spec (arg) + "Remove elements from `buffer-invisibility-spec'." + (if (consp buffer-invisibility-spec) + (setq buffer-invisibility-spec + (delete arg buffer-invisibility-spec))))) + +;; hs-match-data +(defalias 'hs-match-data 'match-data) + +;;--------------------------------------------------------------------------- +;; support functions + +(defun hs-discard-extents (from to) + "Delete hideshow extents in region defined by FROM and TO." + (when (< to from) + (setq from (prog1 to (setq to from)))) + (map-extents #'(lambda (ex ignored) (delete-extent ex)) + (current-buffer) from to nil 'end-closed 'hs)) + +(defun hs-isearch-show (ex) + "Delete extent EX, and set `hs-headline' to nil. + +This function is meant to be used as the `isearch-open-invisible' +property of an extent." + (setq hs-headline nil) + (delete-extent ex)) + +(defun hs-isearch-show-temporary (ex hide-p) + "Hide or show extent EX, and set `hs-headline', all depending on HIDE-P. +If HIDE-P is non-nil, `hs-headline' is set to nil and extent EX is hidden. +Otherwise, `hs-headline' is set to the line of text at the head of EX, and +EX is shown. + +This function is meant to be used as the `isearch-open-invisible-temporary' +property of an extent." + (setq hs-headline + (if hide-p + nil + (or hs-headline + (let ((start (extent-start-position ex))) + (buffer-substring + (save-excursion (goto-char start) + (beginning-of-line) + (skip-chars-forward " \t") + (point)) + start))))) + (force-mode-line-update) + (set-extent-property ex 'invisible (and hide-p 'hs))) + +(defun hs-flag-region (from to flag) + "Hide or show lines from FROM to TO, according to FLAG. +If FLAG is nil then text is shown, while if FLAG is non-nil the text is +hidden. FLAG must be one of the symbols `code' or `comment', depending +on what kind of block is to be hidden." + (when (< to from) + (setq from (prog1 to (setq to from)))) + (save-excursion + ;; first clear it all out + (hs-discard-extents from to) + ;; now create extents if needed + (when flag + (let ((ex (make-extent from to))) + (set-extent-property ex 'invisible 'hs) + (set-extent-property ex 'hs flag) + (when (or (eq hs-isearch-open t) + (eq hs-isearch-open flag) + ;; deprecated backward compatibility -- `block'<=>`code' + (and (eq 'block hs-isearch-open) + (eq 'code flag))) + (set-extent-property ex 'isearch-open-invisible 'hs-isearch-show) + (set-extent-property ex 'isearch-open-invisible-temporary + 'hs-isearch-show-temporary)) + ex)))) + +(defun hs-forward-sexp (match-data arg) + "Adjust point based on MATCH-DATA and call `hs-forward-sexp-func' w/ ARG. +Original match data is restored upon return." + (save-match-data + (set-match-data match-data) + (goto-char (match-beginning hs-block-start-mdata-select)) + (funcall hs-forward-sexp-func arg))) + +(defun hs-hide-comment-region (beg end &optional repos-end) + "Hide a region from BEG to END, marking it as a comment. +Optional arg REPOS-END means reposition at end." + (hs-flag-region (progn (goto-char beg) (end-of-line) (point)) + (progn (goto-char end) (end-of-line) (point)) + 'comment) + (goto-char (if repos-end end beg))) + +(defun hs-hide-block-at-point (&optional end comment-reg) + "Hide block iff on block beginning. +Optional arg END means reposition at end. +Optional arg COMMENT-REG is a list of the form (BEGIN END) and +specifies the limits of the comment, or nil if the block is not +a comment. + +The block beginning is adjusted by `hs-adjust-block-beginning' +and then further adjusted to be at the end of the line." + (if comment-reg + (hs-hide-comment-region (car comment-reg) (cadr comment-reg) end) + (if (looking-at hs-block-start-regexp) + (let* ((mdata (hs-match-data t)) + (pure-p (match-end 0)) + (p + ;; `p' is the point at the end of the block beginning, + ;; which may need to be adjusted + (save-excursion + (goto-char (funcall (or hs-adjust-block-beginning + 'identity) + pure-p)) + ;; whatever the adjustment, we move to eol + (end-of-line) + (point))) + (q + ;; `q' is the point at the end of the block + (progn (hs-forward-sexp mdata 1) + (end-of-line) + (point)))) + (if (and (< p (point)) (> (count-lines p q) 1)) + (set-extent-property (hs-flag-region p q 'code) + 'hs-ofs + (- pure-p p))) + (goto-char (if end q (min p pure-p))))))) + +(defun hs-safety-is-job-n () + "Warn if `buffer-invisibility-spec' does not contain symbol `hs'." + (unless (and (listp buffer-invisibility-spec) + (assq 'hs buffer-invisibility-spec)) + (message "Warning: `buffer-invisibility-spec' does not contain hs!!") + (sit-for 2))) + +(defun hs-inside-comment-p () + "Return non-nil if point is inside a comment, otherwise nil. +Actually, return a list containing the buffer position of the start +and the end of the comment. A comment block can be hidden only if on +its starting line there is only whitespace preceding the actual comment +beginning. If we are inside of a comment but this condition is not met, +we return a list having a nil as its car and the end of comment position +as cdr." + (save-excursion + ;; the idea is to look backwards for a comment start regexp, do a + ;; forward comment, and see if we are inside, then extend extend + ;; forward and backward as long as we have comments + (let ((q (point))) + (when (or (looking-at hs-c-start-regexp) + (re-search-backward hs-c-start-regexp (point-min) t)) + (forward-comment (- (buffer-size))) + (skip-chars-forward " \t\n\f") + (let ((p (point)) + (not-hidable nil)) + (beginning-of-line) + (unless (looking-at (concat "[ \t]*" hs-c-start-regexp)) + ;; we are in this situation: (example) + ;; (defun bar () + ;; (foo) + ;; ) ; comment + ;; ^ + ;; the point was here before doing (beginning-of-line) + ;; here we should advance till the next comment which + ;; eventually has only white spaces preceding it on the same + ;; line + (goto-char p) + (forward-comment 1) + (skip-chars-forward " \t\n\f") + (setq p (point)) + (while (and (< (point) q) + (> (point) p) + (not (looking-at hs-c-start-regexp))) + (setq p (point));; use this to avoid an infinite cycle + (forward-comment 1) + (skip-chars-forward " \t\n\f")) + (if (or (not (looking-at hs-c-start-regexp)) + (> (point) q)) + ;; we cannot hide this comment block + (setq not-hidable t))) + ;; goto the end of the comment + (forward-comment (buffer-size)) + (skip-chars-backward " \t\n\f") + (end-of-line) + (if (>= (point) q) + (list (if not-hidable nil p) (point)))))))) + +(defun hs-grok-mode-type () + "Set up hideshow variables for new buffers. +If `hs-special-modes-alist' has information associated with the +current buffer's major mode, use that. +Otherwise, guess start, end and `comment-start' regexps; `forward-sexp' +function; and adjust-block-beginning function." + (if (and (boundp 'comment-start) + (boundp 'comment-end) + comment-start comment-end) + (let* ((lookup (assoc major-mode hs-special-modes-alist)) + (start-elem (or (nth 1 lookup) "\\s("))) + (if (listp start-elem) + ;; handle (START-REGEXP MDATA-SELECT) + (setq hs-block-start-regexp (car start-elem) + hs-block-start-mdata-select (cadr start-elem)) + ;; backwards compatibility: handle simple START-REGEXP + (setq hs-block-start-regexp start-elem + hs-block-start-mdata-select 0)) + (setq hs-block-end-regexp (or (nth 2 lookup) "\\s)") + hs-c-start-regexp (or (nth 3 lookup) + (let ((c-start-regexp + (regexp-quote comment-start))) + (if (string-match " +$" c-start-regexp) + (substring c-start-regexp + 0 (1- (match-end 0))) + c-start-regexp))) + hs-forward-sexp-func (or (nth 4 lookup) 'forward-sexp) + hs-adjust-block-beginning (nth 5 lookup))) + (progn + (setq hs-minor-mode nil) + (error "%s Mode doesn't support Hideshow Minor Mode" mode-name)))) + +(defun hs-find-block-beginning () + "Reposition point at block-start. +Return point, or nil if original point was not in a block." + (let ((done nil) + (here (point))) + ;; look if current line is block start + (if (looking-at hs-block-start-regexp) + (point) + ;; look backward for the start of a block that contains the cursor + (while (and (re-search-backward hs-block-start-regexp nil t) + (not (setq done + (< here (save-excursion + (hs-forward-sexp (hs-match-data t) 1) + (point))))))) + (if done + (point) + (goto-char here) + nil)))) + +(defun hs-hide-level-recursive (arg minp maxp) + "Recursively hide blocks ARG levels below point in region (MINP MAXP)." + (when (hs-find-block-beginning) + (setq minp (1+ (point))) + (funcall hs-forward-sexp-func 1) + (setq maxp (1- (point)))) + (hs-flag-region minp maxp nil) ; eliminate weirdness + (goto-char minp) + (while (progn + (forward-comment (buffer-size)) + (and (< (point) maxp) + (re-search-forward hs-block-start-regexp maxp t))) + (if (> arg 1) + (hs-hide-level-recursive (1- arg) minp maxp) + (goto-char (match-beginning hs-block-start-mdata-select)) + (hs-hide-block-at-point t))) + (hs-safety-is-job-n) + (goto-char maxp)) + +(defmacro hs-life-goes-on (&rest body) + "Evaluate BODY forms iff variable `hs-minor-mode' is non-nil. +In the dynamic context of this macro `case-fold-search' is t." + `(when hs-minor-mode + (let ((case-fold-search t)) + ,@body))) + +(put 'hs-life-goes-on 'edebug-form-spec '(&rest form)) + +(defun hs-already-hidden-p () + "Return non-nil if point is in an already-hidden block, otherwise nil." + (save-excursion + (let ((c-reg (hs-inside-comment-p))) + (if (and c-reg (nth 0 c-reg)) + ;; point is inside a comment, and that comment is hidable + (goto-char (nth 0 c-reg)) + (if (and (not c-reg) + (hs-find-block-beginning) + (looking-at hs-block-start-regexp)) + ;; point is inside a block + (goto-char (match-end 0))))) + (end-of-line) + (extent-at (point) (current-buffer) 'hs nil 'at))) + +(defun hs-c-like-adjust-block-beginning (initial) + "Adjust INITIAL, the buffer position after `hs-block-start-regexp'. +Actually, point is never moved; a new position is returned that is +the end of the C-function header. This adjustment function is meant +to be assigned to `hs-adjust-block-beginning' for C-like modes." + (save-excursion + (goto-char (1- initial)) + (forward-comment (- (buffer-size))) + (point))) + +;;--------------------------------------------------------------------------- +;; commands + +(defun hs-hide-all () + "Hide all top level blocks, displaying only first and last lines. +Move point to the beginning of the line, and run the normal hook +`hs-hide-hook'. See documentation for `run-hooks'. +If `hs-hide-comments-when-hiding-all' is non-nil, also hide the comments." + (interactive) + (hs-life-goes-on + (message "Hiding all blocks ...") + (save-excursion + (hs-flag-region (point-min) (point-max) nil) ; eliminate weirdness + (goto-char (point-min)) + (let ((count 0) + (re (concat "\\(" + hs-block-start-regexp + "\\)" + (if hs-hide-comments-when-hiding-all + (concat "\\|\\(" + hs-c-start-regexp + "\\)") + "")))) + (while (progn + (unless hs-hide-comments-when-hiding-all + (forward-comment (point-max))) + (re-search-forward re (point-max) t)) + (if (match-beginning 1) + ;; we have found a block beginning + (progn + (goto-char (match-beginning 1)) + (if hs-hide-all-non-comment-function + (funcall hs-hide-all-non-comment-function) + (hs-hide-block-at-point t))) + ;; found a comment, probably + (let ((c-reg (hs-inside-comment-p))) ; blech! + (when (and c-reg (car c-reg)) + (if (> (count-lines (car c-reg) (nth 1 c-reg)) 1) + (hs-hide-block-at-point t c-reg) + (goto-char (nth 1 c-reg)))))) + (message "Hiding ... %d" (setq count (1+ count))))) + (hs-safety-is-job-n)) + (beginning-of-line) + (message "Hiding all blocks ... done") + (run-hooks 'hs-hide-hook))) + +(defun hs-show-all () + "Show everything then run `hs-show-hook'. See `run-hooks'." + (interactive) + (hs-life-goes-on + (message "Showing all blocks ...") + (hs-flag-region (point-min) (point-max) nil) + (message "Showing all blocks ... done") + (run-hooks 'hs-show-hook))) + +(defun hs-hide-block (&optional end) + "Select a block and hide it. With prefix arg, reposition at END. +Upon completion, point is repositioned and the normal hook +`hs-hide-hook' is run. See documentation for `run-hooks'." + (interactive "P") + (hs-life-goes-on + (let ((c-reg (hs-inside-comment-p))) + (cond + ((and c-reg (or (null (nth 0 c-reg)) + (<= (count-lines (car c-reg) (nth 1 c-reg)) 1))) + (message "(not enough comment lines to hide)")) + ((or c-reg + (looking-at hs-block-start-regexp) + (hs-find-block-beginning)) + (hs-hide-block-at-point end c-reg) + (hs-safety-is-job-n) + (run-hooks 'hs-hide-hook)))))) + +(defun hs-show-block (&optional end) + "Select a block and show it. +With prefix arg, reposition at END. Upon completion, point is +repositioned and the normal hook `hs-show-hook' is run. +See documentation for functions `hs-hide-block' and `run-hooks'." + (interactive "P") + (hs-life-goes-on + (or + ;; first see if we have something at the end of the line + (let* ((here (point)) + (buf (current-buffer)) + (ex (extent-at (point-at-eol nil buf) buf 'hs nil 'at))) + (when ex + (goto-char + (cond (end (extent-end-position ex)) + ((eq 'comment (extent-property ex 'hs)) here) + (t (+ (extent-start-position ex) + (extent-property ex 'hs-ofs))))) + (delete-extent ex) + t)) + ;; not immediately obvious, look for a suitable block + (let ((c-reg (hs-inside-comment-p)) + p q) + (cond (c-reg + (when (car c-reg) + (setq p (car c-reg) + q (cadr c-reg)))) + ((and (hs-find-block-beginning) + (looking-at hs-block-start-regexp)) ; fresh match-data, ugh + (setq p (point) + q (progn (hs-forward-sexp (hs-match-data t) 1) (point))))) + (when (and p q) + (hs-flag-region p q nil) + (goto-char (if end q (1+ p))))) + (hs-safety-is-job-n) + (run-hooks 'hs-show-hook)))) + +(defun hs-hide-level (arg) + "Hide all blocks ARG levels below this block. +The hook `hs-hide-hook' is run; see `run-hooks'." + (interactive "p") + (hs-life-goes-on + (save-excursion + (message "Hiding blocks ...") + (hs-hide-level-recursive arg (point-min) (point-max)) + (message "Hiding blocks ... done")) + (hs-safety-is-job-n) + (run-hooks 'hs-hide-hook))) + +(defun hs-toggle-hiding () + "Toggle hiding/showing of a block. +See `hs-hide-block' and `hs-show-block'." + (interactive) + (hs-life-goes-on + (if (hs-already-hidden-p) + (hs-show-block) + (hs-hide-block)))) + +(defun hs-mouse-toggle-hiding (e) + "Toggle hiding/showing of a block. +This command should be bound to a mouse key. +Argument E is a mouse event used by `mouse-set-point'. +See `hs-hide-block' and `hs-show-block'." + (interactive "@e") + (hs-life-goes-on + (mouse-set-point e) + (hs-toggle-hiding))) + +(defun hs-hide-initial-comment-block () + "Hide the first block of comments in a file. +This can be useful if you have huge RCS logs in those comments." + (interactive) + (hs-life-goes-on + (let ((c-reg (save-excursion + (goto-char (point-min)) + (skip-chars-forward " \t\n\f") + (hs-inside-comment-p)))) + (when c-reg + (let ((beg (car c-reg)) (end (cadr c-reg))) + ;; see if we have enough comment lines to hide + (when (> (count-lines beg end) 1) + (hs-hide-comment-region beg end))))))) + +;;;###autoload +(defun hs-minor-mode (&optional arg) + "Toggle hideshow minor mode. +With ARG, turn hideshow minor mode on if ARG is positive, off otherwise. +When hideshow minor mode is on, the menu bar is augmented with hideshow +commands and the hideshow commands are enabled. +The value '(hs . t) is added to `buffer-invisibility-spec'. + +The main commands are: `hs-hide-all', `hs-show-all', `hs-hide-block', +`hs-show-block', `hs-hide-level' and `hs-toggle-hiding'. There is also +`hs-hide-initial-comment-block' and `hs-mouse-toggle-hiding'. + +Turning hideshow minor mode off reverts the menu bar and the +variables to default values and disables the hideshow commands. + +Lastly, the normal hook `hs-minor-mode-hook' is run using `run-hooks'. + +Key bindings: +\\{hs-minor-mode-map}" + + (interactive "P") + (setq hs-headline nil + hs-minor-mode (if (null arg) + (not hs-minor-mode) + (> (prefix-numeric-value arg) 0))) + (if hs-minor-mode + (progn + (hs-grok-mode-type) + (easy-menu-add hs-minor-mode-menu) + (set (make-local-variable 'line-move-ignore-invisible) t) + (add-to-invisibility-spec '(hs . t))) + (easy-menu-remove hs-minor-mode-menu) + (remove-from-invisibility-spec '(hs . t))) + (run-hooks 'hs-minor-mode-hook)) + +;;--------------------------------------------------------------------------- +;; load-time actions + +;; keymaps and menus +(if hs-minor-mode-map + nil + (setq hs-minor-mode-map (make-sparse-keymap)) + (easy-menu-define hs-minor-mode-menu + hs-minor-mode-map + "Menu used when hideshow minor mode is active." + (cons "Hide/Show" + (mapcar + ;; Interpret each table entry as follows: first, populate keymap + ;; with elements 2 and 1; then, for easymenu, use entry directly + ;; unless element 0 is nil, in which case the entry is "omitted". + (lambda (ent) + (define-key hs-minor-mode-map (aref ent 2) (aref ent 1)) + (if (aref ent 0) ent "-----")) + ;; These bindings roughly imitate those used by Outline mode. + ;; menu entry command key + '(["Hide Block" hs-hide-block "\C-c@\C-h"] + ["Show Block" hs-show-block "\C-c@\C-s"] + ["Hide All" hs-hide-all "\C-c@\C-\M-h"] + ["Show All" hs-show-all "\C-c@\C-\M-s"] + ["Hide Level" hs-hide-level "\C-c@\C-l"] + ["Toggle Hiding" hs-toggle-hiding "\C-c@\C-c"] + [nil hs-mouse-toggle-hiding [(shift mouse-2)]] + ))))) + +;; some housekeeping +(or (assq 'hs-minor-mode minor-mode-map-alist) + (setq minor-mode-map-alist + (cons (cons 'hs-minor-mode hs-minor-mode-map) + minor-mode-map-alist))) +(or (assq 'hs-minor-mode minor-mode-alist) + (setq minor-mode-alist (append minor-mode-alist + (list '(hs-minor-mode " hs"))))) + +;; make some variables permanently buffer-local +(let ((vars '(hs-minor-mode + hs-c-start-regexp + hs-block-start-regexp + hs-block-start-mdata-select + hs-block-end-regexp + hs-forward-sexp-func + hs-adjust-block-beginning))) + (while vars + (let ((var (car vars))) + (make-variable-buffer-local var) + (put var 'permanent-local t)) + (setq vars (cdr vars)))) + +;;--------------------------------------------------------------------------- +;; that's it + +(provide 'hideshow) + +;;; hideshow.el ends here diff --git a/xemacs-packages/lisp/c-support/hideshow.elc b/xemacs-packages/lisp/c-support/hideshow.elc new file mode 100644 index 0000000000000000000000000000000000000000..d7b9cce515960cbc3085af7169115ef5a27abbf2 GIT binary patch literal 19130 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 z + + * Makefile (VERSION): XEmacs package 0.20 released. + +2005-05-30 Reiner Steib + + * encrypt.el (encrypt-xor-process-buffer): Replace `string-to-int' + by `string-to-number'. + +2005-05-17 Katsumi Yamaoka + + * encrypt.el (encrypt): Add :group. + +2005-02-22 Simon Josefsson + + * encrypt.el (encrypt-password-cache-expiry): Remove (use + `password-cache-expiry' instead). Reported by Arne Jørgensen + . + (encrypt): Add password-cache and password-cache-expiry as group + members. + +2004-01-05 Simon Josefsson + + * md4.el (print-int32, print-string-hexa): Remove. Suggested by + Jesper Harder . + +2004-11-30 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.19 released. + +2004-11-29 Simon Josefsson + + * encrypt.el: New file. + + * Makefile (ELCS): Add encrypt.elc. + +2004-09-16 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.18 released. + +2004-09-16 Simon Josefsson + + * hex-util.el: Add arch-tag cookie. + +2004-09-12 Simon Josefsson + + * sha1-dl.el: Removed. + +2004-09-12 Simon Josefsson + + * sha1-el.el, password.el: Gnus CVS sync changes for the the + following ChangeLog entries, until 2004-02-09 below. + +2004-09-01 Simon Josefsson + + * sha1-el.el: Renamed to sha1.el. + +2004-08-04 Teodor Zlatanov + + * password.el: add comments on using password-read-and-add + (password-read-and-add): new function to read and add the + password to the cache at once + +2004-03-05 Jesper Harder + + * sha1-el.el (sha1-maximum-internal-length): Doc fix. + +2004-03-04 Katsumi Yamaoka + + * password.el: Don't autoload run-at-time for Emacs. + + * sha1-el.el: Don't autoload executable-find. + +2004-01-07 Katsumi Yamaoka + + * sha1-el.el (sha1-string-external): Use with-temp-buffer. + +2004-01-07 Katsumi Yamaoka + + * sha1-el.el (sha1-string-external): Make it can return a string + in binary form. + (sha1-region-external): Ditto. + (sha1-string-internal): Ditto. + (sha1-region-internal): Ditto. + (sha1-region): Ditto. + (sha1-string): Ditto. + (sha1): Ditto. + +2004-02-09 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.17 released. + +2004-02-06 Simon Josefsson + + * sha1-el.el: Gnus CVS sync changes for the the following + ChangeLog entries, until 2004-01-07 below, suggested by Steve + Youngs . + +2004-01-07 Katsumi Yamaoka + + * sha1-el.el (sha1-string-external): Use with-temp-buffer. + +2004-01-07 Katsumi Yamaoka + + * sha1-el.el (sha1-string-external): Make it can return a string + in binary form. + (sha1-region-external): Ditto. + (sha1-string-internal): Ditto. + (sha1-region-internal): Ditto. + (sha1-region): Ditto. + (sha1-string): Ditto. + (sha1): Ditto. + +2004-01-17 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.16 released. + +2004-01-16 Simon Josefsson + + * password.el: Add. + + * Makefile (REQUIRES): Add xemacs-base. + (ELCS): Add password.el. + +2003-12-16 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.15 released. + +2003-12-15 Simon Josefsson + + * hex-util.el, sha1-el.el: Gnus CVS sync changes for the following + ChangeLog entries, until 2001-12-29 below. + +2003-12-16 Simon Josefsson + + * sha1-el.el (autoload): Don't use ignore-errors. + (sha1-use-external): Use condition-case. Suggested by Katsumi + Yamaoka . + +2003-12-15 Simon Josefsson + + * sha1-el.el (autoload): Ignore errors for + executable-find. (XEmacs ecrypto does not require sh-script where + executable.el is located.) + (sha1-use-external): Likewise. + + * sha1-el.el (sha1): Add defgroup. + (sha1-maximum-internal-length, sha1-program, sha1-use-external) + (sha1-program): Use 'sha1sum' from GNU CoreUtils instead of OpenSSL. + (sha1): Autoload. + +2002-02-20 Katsumi Yamaoka + + * hex-util.el: Remove trailing whitespaces, replace spc+tab with + tab, replace leading whitespaces with tabs. + +2001-12-29 ShengHuo ZHU + + * sha1-el.el (sha1-use-external): New variable. + (sha1-region): Use it. + (sha1-string): Ditto. + +2003-10-31 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.14 released. + +2003-06-22 Norbert Koch + + * Makefile (VERSION): XEmacs package 0.13 released. + +2003-06-21 Simon Josefsson + + * blowfish.el (blowfish-add, blowfish-f, blowfish-s-box-inits) + (blowfish-p-array-inits): Use #xCAFE instead of ?\xCAFE, suggested + by "Stephen J. Turnbull" and reported by + sigurd@12move.de (Karl Pflästerer). + +2003-03-09 Ben Wing + + * Makefile: + Delete explicit compile:: and binkit: rules. + +2002-11-29 Ben Wing + + * .cvsignore: Remove files now handled automatically by CVS. + * Makefile: Use `compile' instead of hard-coded `all'. + +2002-10-15 Ville Skyttä + + * Makefile (srckit): Remove. + +2002-09-25 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 0.12 released. + +2002-09-17 Ville Skyttä + + * md5-el.el (md5-update): Comment typo fix. + +2002-08-12 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 0.11 released. + +2002-08-07 Ville Skyttä + + * Package moved to official location in xemacs-packages. + +2002-08-02 Simon Josefsson + + * hex-util.el: New file. + + * package-info.in: Fix package name, fix provides. + + * sha1-el.el (sha1): autoload. + + * md5-el.el (md5): autoload. + (md5-program, md5-maximum-internal-length): defcustom. + + * md4.el (md4): autoload. + + * sha1.el, sha1-el.el, sha1-dl.el, md5.el, md5-el.el, md5-dl.el: + Replace with versions from FLIM. Supports emacsen that can load + dynamic libraries, otherwise should be equal. + + * Makefile (PACKAGE): Fix package name. + (ELCS): Add md4.elc md5.elc md5-el.elc md5-dl.elc sha1.elc + sha1-el.elc sha1-dl.elc hex-util.elc. + +2002-08-01 Ville Skyttä + + * .cvsignore: New. + + * Makefile: Fix path to XEmacs.rules. + (CATEGORY): Change to unsupported. + + * package-info.in (distribution): Change to unsupported. + +2002-06-13 Simon Josefsson + + * ecrypto: New package, from Ecrypto2.0.tgz (29436 bytes, MD5 + 01e74632426b429b9468158ad52ef973) from + http://web.mit.edu/thouis/www/ecrypto.html written by Ray Jones + . diff --git a/xemacs-packages/lisp/ecrypto/_pkg.el b/xemacs-packages/lisp/ecrypto/_pkg.el new file mode 100644 index 00000000..635f477f --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/_pkg.el @@ -0,0 +1,5 @@ +;;;###autoload +(package-provide 'ecrypto + :version 0.20 + :author-version "2.0" + :type 'regular) diff --git a/xemacs-packages/lisp/ecrypto/ascii-armor.el b/xemacs-packages/lisp/ecrypto/ascii-armor.el new file mode 100644 index 00000000..93028589 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/ascii-armor.el @@ -0,0 +1,138 @@ +;;; ascii-armor.el -- translate data into and from ascii-armor +;;; (radix64) + +;; Copyright (C) 1998 Ray Jones + +;; Author: Ray Jones, rjones@pobox.com +;; Keywords: base64, ascii-armor, radix64, oink +;; Created: 1998-04-14 + +;; This program 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 program 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 this program; if not, you can either send email to this +;; program's maintainer or write to: The Free Software Foundation, +;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. + +;;; Commentary: + +;;; Code: + +(require 'cl) + +(defun ascii-armor-char (val) + (cond ((< val 26) (+ val ?A)) + ((< val 52) (+ (- val 26) ?a)) + ((< val 62) (+ (- val 52) ?0)) + ((= val 62) ?+) + ((= val 63) ?/) + (t (error "no ascii-armor character for %d!" val)))) + +(defun ascii-armor-val (char) + (cond ((and (<= ?A char) (<= char ?Z)) (- char ?A)) + ((and (<= ?a char) (<= char ?z)) (+ (- char ?a) 26)) + ((and (<= ?0 char) (<= char ?9)) (+ (- char ?0) 52)) + ((= char ?+) 62) + ((= char ?/) 63) + (t nil))) + +(defun ascii-armor-length (n) + "calculate the number of characters needed to encode N octets." + + (let* ( + ;; number of bits + (n1 (* n 8)) + ;; ascii armor is 6 bits per symbol... + (n2 (car (ceiling* n1 6))) + ;; but always a multiple of 4 symbols + (n3 (* 4 (car (ceiling* n2 4))))) + n3)) + +(defun ascii-armor-data-length (str) + "calculate the number of octets stored in an ascii-armor string" + + (let ((len (length str))) + (while (and (> len 0) + (eq ?= (aref str (1- len)))) + (decf len)) + (/ (* len 6) 8))) + +;; translate a vector of 16-bit values into an ascii-armor string +(defun vec16-to-ascii-armor (vec) + (let* ((in-len (length vec)) + (out-len (ascii-armor-length (* 2 in-len))) + (out-str (make-string out-len ?=)) + (out-idx 0) + (bits-start 0)) + ;; helper function + (flet ((next-out (val) + (aset out-str out-idx + (ascii-armor-char + (logand ?\x3f val))) + (incf out-idx))) + + (dotimes (in-idx in-len) + (incf bits-start 16) + ;; read out as many bits from the current index as possible + (while (> bits-start 0) + ;; do the next 6 bits straddle a boundary in vec? + + (if (< bits-start 6) + ;; straddle + (let ((hi-val (aref vec in-idx)) + ;; pad with 0s + (lo-val (if (< in-idx (1- in-len)) + (aref vec (1+ in-idx)) + 0))) + (next-out (logior + (ash hi-val (- 6 bits-start)) + (ash lo-val (- 6 bits-start 16))))) + + ;; 6 bits all from the current entry in vec + (next-out (ash (aref vec in-idx) (- 6 bits-start)))) + + (decf bits-start 6)))) + + ;; pad with ?=, if out-str isn't full + (while (< out-idx out-len) + (aset out-str out-idx ?=) + (incf out-idx)) + + out-str)) + +;; translate an ascii-armor string to a 16-bit vector +(defun ascii-armor-to-vec16 (string) + ;; ascii armor is padded, so this doesn't have to be rounded, just + ;; truncated. + (let* ((out-len (/ (ascii-armor-data-length string) 2)) + (out-vec (make-vector out-len 0)) + (buf 0) + (bits-in-buf 0) + (in-idx 0)) + (dotimes (out-idx out-len) + ;; shift bits from the string until there are enough to stick + ;; into the output vector + (while (< bits-in-buf 16) + (let ((val (ascii-armor-val (aref string in-idx)))) + (when val + (setq buf (logior (ash buf 6) + val)) + (incf bits-in-buf 6)) + (incf in-idx))) + + (aset out-vec out-idx (ash buf (- 16 bits-in-buf))) + (decf bits-in-buf 16) + ;; turn off the used bits + (setq buf (logand buf (lognot (ash ?\xffff bits-in-buf))))) + + out-vec)) + +(provide 'ascii-armor) diff --git a/xemacs-packages/lisp/ecrypto/ascii-armor.elc b/xemacs-packages/lisp/ecrypto/ascii-armor.elc new file mode 100644 index 0000000000000000000000000000000000000000..e02ee2b06352529b58105d3ede6292b87d4f5f76 GIT binary patch literal 2268 zcmZ`)TW=ai6wc#<0ja*UaW3v*X=QM!W!B%>T`1`qMKOdZHfLwa^zotalNkV&U+`VNY&U4|mM zfK;oE^8Naju!(+544+YxQxJCu*Gr(zBtZV9QZCrATyo8_Bg5J~;TM)Fx@jc+5dn(0{E4mZo@OTtAg(?imobzZ^;pBys6Wk*@D~on!a?px0B<4U<87(^=;NzT00cUdpaQ3B-A2HAQ z6c9O5NFn|_WDryAHZsBcq*pA$Dew{nhPp@WcJYje2aHk!uQ0cPGNDlT4Q!;yz2uJ< zmB6BGotFePCQ8tJdSy>z`j zn46kRbbwA>2($wQJZ`%P5-$qD@7aaN4I$_Yks5>(RC^CDS_{DUYooi58}FsS@?w)T z-UgOy-_==Q@9F-BgusnffM)q`Eq-a9im|CFDtU45hLA zqX&VSrbRCwN=KSJHq@$Jy?)$|*2aGL_`3b;*yT^}+b0jJf!4LL;ZS6FwecnVS<`AG zt;da>@abx!uCdT!D6our#@WhZ{Z(shWbFI)m#>lUPs2G){u&wiTa20I96hKGtkj0;PGm?CbnOaWQlx7#e?Z_MmP}(y zEQz6Da!>I%ae064dwDIB4T`&>4kBS`D0W)_qgz}-R}hbjj;i?Tk^_ymyVApI{Y`T> zTHO@@V(P8fyn^m{QSrzoRg}4@x%3poGH2_)%g)A4lx){=5o1@FzlWkvB+mLmKx56l zeZ1?@2UU%&)CNT$aUTUWQQ#iMzOr>%i)F8i=9|^Bc`QCw@UC4hV`pD7v1MAMTrdcT zb~djuY^dFZ$9I+z8q*l|19cjYp%W831o29ssOfJ(W0O83!^SrT^%PFaPKT2?p$K>- z(;s4)7{t_A9_G%gtsgCF&KI8`-AO+R?jSN4J^V0w6liJk+0ChKxAmO z(F`B2HvVcy1~s;b3LI|y`ROF|S(78fnmjCYH-f1eOw{wzz)9#>sOmvAe4HCO4ShL5 zorPmjwDYwyJ0X43PERmh4GF>Yl3S=0JK{khiFrT#{;Qb*Uqt8$?>Q<6bJ%Yx64RGa oKfR(xxF%kr*?+oi08@5BerG`VC>Fa3bzFPX#8%h;Vo3!51vqH)AOHXW literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/auto-autoloads.el b/xemacs-packages/lisp/ecrypto/auto-autoloads.el new file mode 100644 index 00000000..91d52e26 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/auto-autoloads.el @@ -0,0 +1,49 @@ +;;; DO NOT MODIFY THIS FILE +(if (featurep 'ecrypto-autoloads) (error "Already loaded")) + +;;;### (autoloads nil "_pkg" "ecrypto/_pkg.el") + +(package-provide 'ecrypto :version 0.2 :author-version "2.0" :type 'regular) + +;;;*** + +;;;### (autoloads (encrypt-insert-file-contents encrypt-find-model) "encrypt" "ecrypto/encrypt.el") + +(autoload 'encrypt-find-model "encrypt" "\ +Given a filename, find a encrypt-file-alist entry" nil nil) + +(autoload 'encrypt-insert-file-contents "encrypt" "\ +Decrypt FILE into the current buffer." t nil) + +;;;*** + +;;;### (autoloads (md4) "md4" "ecrypto/md4.el") + +(autoload 'md4 "md4" "\ +Returns the MD4 hash string of 16 bytes long for a string IN of N +bytes long. N is required to handle strings containing character 0." nil nil) + +;;;*** + +;;;### (autoloads (md5) "md5-el" "ecrypto/md5-el.el") + +(autoload 'md5 "md5-el" "\ +Return the MD5 (a secure message digest algorithm) of an object. +OBJECT is either a string or a buffer. +Optional arguments START and END denote buffer positions for computing the +hash of a portion of OBJECT." nil nil) + +;;;*** + +;;;### (autoloads (sha1) "sha1" "ecrypto/sha1.el") + +(autoload 'sha1 "sha1" "\ +Return the SHA1 (Secure Hash Algorithm) of an object. +OBJECT is either a string or a buffer. +Optional arguments BEG and END denote buffer positions for computing the +hash of a portion of OBJECT. +If BINARY is non-nil, return a string in binary form." nil nil) + +;;;*** + +(provide 'ecrypto-autoloads) diff --git a/xemacs-packages/lisp/ecrypto/auto-autoloads.elc b/xemacs-packages/lisp/ecrypto/auto-autoloads.elc new file mode 100644 index 0000000000000000000000000000000000000000..46b90562d252d02c2f9fe2d1354a22d7c5605cb8 GIT binary patch literal 1779 zcmb_cO>f&q5cRDn&%O7BDQXc2DUy*aOTI*o)x?3L0G1CeiUM7cD{*6Tmsu{IsOJFb zf9ap-_vfGLEJ;~a++zfY63N+__ujmjli9`NPYw^rxN2KU+nW&V0UuS}FqzY0Q@He6|5E3nhXdF0BPpr^mGDUBxYMGWe zY`J%IJm+Kdlzu;?R7p0OY-7Op@9B*F^eUr;T>Ck%suFu?;l`osd7jh6ajmI@`|TZh z5Am8+yWX!Ts)gR1Ch!*77I#u>&86{eZ~UB?dW3+RSGe;6Qsh*d&Rgw$s}$THf4cX> z+n;~A_x-QG{r<=O4Xu@%4%`Q)_Zn=Yd`O(ZQbPnzM8RTbHLUI@kE6RyTq& zcL%YR3tSY{jF=t+5Av&Vrr|~4AxtZ2R_nZUg4d?tK8v?RaSZsur5|2I0@h<~09pMr$i+ zn2_X9BpEG~#Bfc$*`rjX1Gsd#6)FnD@t#s~IPQRVxQ8?=s5qI9qaf$g0zoQhix{wc zt+X&%;aRv$LM>nN#01WZ(`U2CR~9d)*97C1S;Mju+j&8=uO!RC^tvt@Sr=E+%PUHi zVm3cRO54!zt~n@GCF}v(3zWvLnA%vjRKaPqwIC=;H@k#xS{UyuFtiE`eV*?`h{l6` z5r*M^MOZwYM(8bC4W8OAPCq>J)7g^`%-cC%;q-hyz5L2{LMrLgL_8o1SzGQ}Li=+m jB-0x!Yq76Zm9Yq}z3#*s49V!Xv(?+Kg~K}w#dH1zP^e1A literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/blowfish.el b/xemacs-packages/lisp/ecrypto/blowfish.el new file mode 100644 index 00000000..7febd6bc --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/blowfish.el @@ -0,0 +1,482 @@ +;;; blowfish.el -- block cipher + +;; Copyright (C) 1998 Ray Jones + +;; Author: Ray Jones, rjones@pobox.com +;; Keywords: Blowfish, Schneier, oink, cipher, cypher, cryptography +;; Created: 1998-04-01 + +;; This program 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 program 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 this program; if not, you can either send email to this +;; program's maintainer or write to: The Free Software Foundation, +;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. + +;;; Commentary: + +;; this code is Bruce Schneier's Blowfish encryption algorithm. it is +;; fast, license-free, unpatented, and beleived secure. it takes a +;; key of length 32-448 bits. it works on 64-bit blocks. further +;; information is available in Applied Cryptography by Schneier or at +;; http://www.counterpane.com/blowfish.html + +;; to use, given a key: +;; +;; (let ((subkeys (blowfish-generate-keys key)) ;; returns a pair, the +;; ;; P-array and the S-boxes +;; (data [1 2 3 4])) +;; ;; encipher data in place +;; (blowfish-cipher-block data (car subkeys) (cdr subkeys)) +;; ;; decipher in place +;; (blowfish-cipher-block data (car subkeys) (cdr subkeys) 'decrypt) +;; ;; data should now be back to its starting value +;; (assert (equal data [1 2 3 4]))) + +;; note: the time taken to generate subkeys is quite substantial, but +;; encryption and decryption afterwards is quite fast. + +;; keys are vectors of 16-bit integers, with the vector being a +;; positive, even number of elements long. + + +;;; Code: +(require 'cl) + +;; blowfish is a 64-bit algorithm, which operates on 32-bit pieces. +;; this code stores 32-bit numbers as vectors w/ 2 16-bit elements. + +;; helper functions +(defsubst blowfish-xor (a b result) + (aset result 0 (logxor (aref a 0) (aref b 0))) + (aset result 1 (logxor (aref a 1) (aref b 1))) + (assert (and (< (aref result 0) (ash 1 16)) + (< (aref result 1) (ash 1 16))) nil + "")) + +(defsubst blowfish-add (a b result) + (let* ((low (+ (aref a 1) (aref b 1))) + (high (logand (+ (aref a 0) (aref b 0) (ash low -16)) + #xFFFF))) + (aset result 0 high) + (aset result 1 (logand low #xFFFF))) + (assert (and (< (aref result 0) (ash 1 16)) + (< (aref result 1) (ash 1 16))) nil + "")) + +(defun blowfish-cipher-block (data p-array s-boxes &optional direction) + "encode or decode with the blowfish cipher, in place. +first arg is vector of 4 16-bit words (MSB order). +second arg is P-array to encrypt/decrypt with. +third arg is S-boxes to encrypt/decrypt with. +optional fourth arg is direction \(eq 'decrypt to decrypt\)." + + ;; split the data into two 32 bit pieces (stored as 2 16-bit pieces + ;; each.) + (let ((xl (vector (aref data 0) (aref data 1))) + (xr (vector (aref data 2) (aref data 3))) + (reverse (eq direction 'decrypt))) + ;; 16 rounds + (dotimes (idx 16) + ;; mix in the p-array. note the reverse order for decryption. + (let ((p-val (aref p-array (if reverse (- 17 idx) idx)))) + (blowfish-xor xl p-val xl)) + ;; apply F + (blowfish-f xl s-boxes xr) + ;; swap low and high 32 bits + (rotatef xl xr)) + + ;; undo the last swap + (rotatef xl xr) + ;; mixin last two elements of P-array + ;; (when comparing to section in AC 2nd Ed, note that this is 0 + ;; indexed, and the reverse order for decryption. + (let ((p-val-16 (aref p-array (if reverse 1 16))) + (p-val-17 (aref p-array (if reverse 0 17)))) + (blowfish-xor xl p-val-17 xl) + (blowfish-xor xr p-val-16 xr)) + + ;; put the result back into the input vector + (aset data 0 (aref xl 0)) + (aset data 1 (aref xl 1)) + (aset data 2 (aref xr 0)) + (aset data 3 (aref xr 1)) + + ;; clean up + (fillarray xl 0) + (fillarray xr 0))) + +(defvar *blowfish-f-scratch* [0 0] + "scratch area for the blowfish-f function, to reduce allocation") + +(defun blowfish-f (x s-boxes dest) + "perform the blowfish F-function. takes vector of two-16-bit +numbers and S-boxes to use as args, and the destination to xor the +result into. uses *blowfish-f-scratch* to reduce allocation." + ;; S-boxes are indexed into via 8-bit pieces of X + (let* ((x0 (aref x 0)) + (Sa (aref (aref s-boxes 0) (ash x0 -8))) + (Sb (aref (aref s-boxes 1) (logand x0 #xFF))) + (x1 (aref x 1)) + (Sc (aref (aref s-boxes 2) (ash x1 -8))) + (Sd (aref (aref s-boxes 3) (logand x1 #xFF)))) + + (blowfish-add Sa Sb *blowfish-f-scratch*) + (blowfish-xor Sc *blowfish-f-scratch* *blowfish-f-scratch*) + (blowfish-add Sd *blowfish-f-scratch* *blowfish-f-scratch*) + (blowfish-xor *blowfish-f-scratch* dest dest))) + +;; initialization constants for the P-array and S-boxes + +(defconst blowfish-s-box-inits + [ + [ + [#xd131 #x0ba6] [#x98df #xb5ac] [#x2ffd #x72db] [#xd01a #xdfb7] + [#xb8e1 #xafed] [#x6a26 #x7e96] [#xba7c #x9045] [#xf12c #x7f99] + [#x24a1 #x9947] [#xb391 #x6cf7] [#x0801 #xf2e2] [#x858e #xfc16] + [#x6369 #x20d8] [#x7157 #x4e69] [#xa458 #xfea3] [#xf493 #x3d7e] + [#x0d95 #x748f] [#x728e #xb658] [#x718b #xcd58] [#x8215 #x4aee] + [#x7b54 #xa41d] [#xc25a #x59b5] [#x9c30 #xd539] [#x2af2 #x6013] + [#xc5d1 #xb023] [#x2860 #x85f0] [#xca41 #x7918] [#xb8db #x38ef] + [#x8e79 #xdcb0] [#x603a #x180e] [#x6c9e #x0e8b] [#xb01e #x8a3e] + [#xd715 #x77c1] [#xbd31 #x4b27] [#x78af #x2fda] [#x5560 #x5c60] + [#xe655 #x25f3] [#xaa55 #xab94] [#x5748 #x9862] [#x63e8 #x1440] + [#x55ca #x396a] [#x2aab #x10b6] [#xb4cc #x5c34] [#x1141 #xe8ce] + [#xa154 #x86af] [#x7c72 #xe993] [#xb3ee #x1411] [#x636f #xbc2a] + [#x2ba9 #xc55d] [#x7418 #x31f6] [#xce5c #x3e16] [#x9b87 #x931e] + [#xafd6 #xba33] [#x6c24 #xcf5c] [#x7a32 #x5381] [#x2895 #x8677] + [#x3b8f #x4898] [#x6b4b #xb9af] [#xc4bf #xe81b] [#x6628 #x2193] + [#x61d8 #x09cc] [#xfb21 #xa991] [#x487c #xac60] [#x5dec #x8032] + [#xef84 #x5d5d] [#xe985 #x75b1] [#xdc26 #x2302] [#xeb65 #x1b88] + [#x2389 #x3e81] [#xd396 #xacc5] [#x0f6d #x6ff3] [#x83f4 #x4239] + [#x2e0b #x4482] [#xa484 #x2004] [#x69c8 #xf04a] [#x9e1f #x9b5e] + [#x21c6 #x6842] [#xf6e9 #x6c9a] [#x670c #x9c61] [#xabd3 #x88f0] + [#x6a51 #xa0d2] [#xd854 #x2f68] [#x960f #xa728] [#xab51 #x33a3] + [#x6eef #x0b6c] [#x137a #x3be4] [#xba3b #xf050] [#x7efb #x2a98] + [#xa1f1 #x651d] [#x39af #x0176] [#x66ca #x593e] [#x8243 #x0e88] + [#x8cee #x8619] [#x456f #x9fb4] [#x7d84 #xa5c3] [#x3b8b #x5ebe] + [#xe06f #x75d8] [#x85c1 #x2073] [#x401a #x449f] [#x56c1 #x6aa6] + [#x4ed3 #xaa62] [#x363f #x7706] [#x1bfe #xdf72] [#x429b #x023d] + [#x37d0 #xd724] [#xd00a #x1248] [#xdb0f #xead3] [#x49f1 #xc09b] + [#x0753 #x72c9] [#x8099 #x1b7b] [#x25d4 #x79d8] [#xf6e8 #xdef7] + [#xe3fe #x501a] [#xb679 #x4c3b] [#x976c #xe0bd] [#x04c0 #x06ba] + [#xc1a9 #x4fb6] [#x409f #x60c4] [#x5e5c #x9ec2] [#x196a #x2463] + [#x68fb #x6faf] [#x3e6c #x53b5] [#x1339 #xb2eb] [#x3b52 #xec6f] + [#x6dfc #x511f] [#x9b30 #x952c] [#xcc81 #x4544] [#xaf5e #xbd09] + [#xbee3 #xd004] [#xde33 #x4afd] [#x660f #x2807] [#x192e #x4bb3] + [#xc0cb #xa857] [#x45c8 #x740f] [#xd20b #x5f39] [#xb9d3 #xfbdb] + [#x5579 #xc0bd] [#x1a60 #x320a] [#xd6a1 #x00c6] [#x402c #x7279] + [#x679f #x25fe] [#xfb1f #xa3cc] [#x8ea5 #xe9f8] [#xdb32 #x22f8] + [#x3c75 #x16df] [#xfd61 #x6b15] [#x2f50 #x1ec8] [#xad05 #x52ab] + [#x323d #xb5fa] [#xfd23 #x8760] [#x5331 #x7b48] [#x3e00 #xdf82] + [#x9e5c #x57bb] [#xca6f #x8ca0] [#x1a87 #x562e] [#xdf17 #x69db] + [#xd542 #xa8f6] [#x287e #xffc3] [#xac67 #x32c6] [#x8c4f #x5573] + [#x695b #x27b0] [#xbbca #x58c8] [#xe1ff #xa35d] [#xb8f0 #x11a0] + [#x10fa #x3d98] [#xfd21 #x83b8] [#x4afc #xb56c] [#x2dd1 #xd35b] + [#x9a53 #xe479] [#xb6f8 #x4565] [#xd28e #x49bc] [#x4bfb #x9790] + [#xe1dd #xf2da] [#xa4cb #x7e33] [#x62fb #x1341] [#xcee4 #xc6e8] + [#xef20 #xcada] [#x3677 #x4c01] [#xd07e #x9efe] [#x2bf1 #x1fb4] + [#x95db #xda4d] [#xae90 #x9198] [#xeaad #x8e71] [#x6b93 #xd5a0] + [#xd08e #xd1d0] [#xafc7 #x25e0] [#x8e3c #x5b2f] [#x8e75 #x94b7] + [#x8ff6 #xe2fb] [#xf212 #x2b64] [#x8888 #xb812] [#x900d #xf01c] + [#x4fad #x5ea0] [#x688f #xc31c] [#xd1cf #xf191] [#xb3a8 #xc1ad] + [#x2f2f #x2218] [#xbe0e #x1777] [#xea75 #x2dfe] [#x8b02 #x1fa1] + [#xe5a0 #xcc0f] [#xb56f #x74e8] [#x18ac #xf3d6] [#xce89 #xe299] + [#xb4a8 #x4fe0] [#xfd13 #xe0b7] [#x7cc4 #x3b81] [#xd2ad #xa8d9] + [#x165f #xa266] [#x8095 #x7705] [#x93cc #x7314] [#x211a #x1477] + [#xe6ad #x2065] [#x77b5 #xfa86] [#xc754 #x42f5] [#xfb9d #x35cf] + [#xebcd #xaf0c] [#x7b3e #x89a0] [#xd641 #x1bd3] [#xae1e #x7e49] + [#x0025 #x0e2d] [#x2071 #xb35e] [#x2268 #x00bb] [#x57b8 #xe0af] + [#x2464 #x369b] [#xf009 #xb91e] [#x5563 #x911d] [#x59df #xa6aa] + [#x78c1 #x4389] [#xd95a #x537f] [#x207d #x5ba2] [#x02e5 #xb9c5] + [#x8326 #x0376] [#x6295 #xcfa9] [#x11c8 #x1968] [#x4e73 #x4a41] + [#xb347 #x2dca] [#x7b14 #xa94a] [#x1b51 #x0052] [#x9a53 #x2915] + [#xd60f #x573f] [#xbc9b #xc6e4] [#x2b60 #xa476] [#x81e6 #x7400] + [#x08ba #x6fb5] [#x571b #xe91f] [#xf296 #xec6b] [#x2a0d #xd915] + [#xb663 #x6521] [#xe7b9 #xf9b6] [#xff34 #x052e] [#xc585 #x5664] + [#x53b0 #x2d5d] [#xa99f #x8fa1] [#x08ba #x4799] [#x6e85 #x076a] + ] + [ + [#x4b7a #x70e9] [#xb5b3 #x2944] [#xdb75 #x092e] [#xc419 #x2623] + [#xad6e #xa6b0] [#x49a7 #xdf7d] [#x9cee #x60b8] [#x8fed #xb266] + [#xecaa #x8c71] [#x699a #x17ff] [#x5664 #x526c] [#xc2b1 #x9ee1] + [#x1936 #x02a5] [#x7509 #x4c29] [#xa059 #x1340] [#xe418 #x3a3e] + [#x3f54 #x989a] [#x5b42 #x9d65] [#x6b8f #xe4d6] [#x99f7 #x3fd6] + [#xa1d2 #x9c07] [#xefe8 #x30f5] [#x4d2d #x38e6] [#xf025 #x5dc1] + [#x4cdd #x2086] [#x8470 #xeb26] [#x6382 #xe9c6] [#x021e #xcc5e] + [#x0968 #x6b3f] [#x3eba #xefc9] [#x3c97 #x1814] [#x6b6a #x70a1] + [#x687f #x3584] [#x52a0 #xe286] [#xb79c #x5305] [#xaa50 #x0737] + [#x3e07 #x841c] [#x7fde #xae5c] [#x8e7d #x44ec] [#x5716 #xf2b8] + [#xb03a #xda37] [#xf050 #x0c0d] [#xf01c #x1f04] [#x0200 #xb3ff] + [#xae0c #xf51a] [#x3cb5 #x74b2] [#x2583 #x7a58] [#xdc09 #x21bd] + [#xd191 #x13f9] [#x7ca9 #x2ff6] [#x9432 #x4773] [#x22f5 #x4701] + [#x3ae5 #xe581] [#x37c2 #xdadc] [#xc8b5 #x7634] [#x9af3 #xdda7] + [#xa944 #x6146] [#x0fd0 #x030e] [#xecc8 #xc73e] [#xa475 #x1e41] + [#xe238 #xcd99] [#x3bea #x0e2f] [#x3280 #xbba1] [#x183e #xb331] + [#x4e54 #x8b38] [#x4f6d #xb908] [#x6f42 #x0d03] [#xf60a #x04bf] + [#x2cb8 #x1290] [#x2497 #x7c79] [#x5679 #xb072] [#xbcaf #x89af] + [#xde9a #x771f] [#xd993 #x0810] [#xb38b #xae12] [#xdccf #x3f2e] + [#x5512 #x721f] [#x2e6b #x7124] [#x501a #xdde6] [#x9f84 #xcd87] + [#x7a58 #x4718] [#x7408 #xda17] [#xbc9f #x9abc] [#xe94b #x7d8c] + [#xec7a #xec3a] [#xdb85 #x1dfa] [#x6309 #x4366] [#xc464 #xc3d2] + [#xef1c #x1847] [#x3215 #xd908] [#xdd43 #x3b37] [#x24c2 #xba16] + [#x12a1 #x4d43] [#x2a65 #xc451] [#x5094 #x0002] [#x133a #xe4dd] + [#x71df #xf89e] [#x1031 #x4e55] [#x81ac #x77d6] [#x5f11 #x199b] + [#x0435 #x56f1] [#xd7a3 #xc76b] [#x3c11 #x183b] [#x5924 #xa509] + [#xf28f #xe6ed] [#x97f1 #xfbfa] [#x9eba #xbf2c] [#x1e15 #x3c6e] + [#x86e3 #x4570] [#xeae9 #x6fb1] [#x860e #x5e0a] [#x5a3e #x2ab3] + [#x771f #xe71c] [#x4e3d #x06fa] [#x2965 #xdcb9] [#x99e7 #x1d0f] + [#x803e #x89d6] [#x5266 #xc825] [#x2e4c #xc978] [#x9c10 #xb36a] + [#xc615 #x0eba] [#x94e2 #xea78] [#xa5fc #x3c53] [#x1e0a #x2df4] + [#xf2f7 #x4ea7] [#x361d #x2b3d] [#x1939 #x260f] [#x19c2 #x7960] + [#x5223 #xa708] [#xf713 #x12b6] [#xebad #xfe6e] [#xeac3 #x1f66] + [#xe3bc #x4595] [#xa67b #xc883] [#xb17f #x37d1] [#x018c #xff28] + [#xc332 #xddef] [#xbe6c #x5aa5] [#x6558 #x2185] [#x68ab #x9802] + [#xeece #xa50f] [#xdb2f #x953b] [#x2aef #x7dad] [#x5b6e #x2f84] + [#x1521 #xb628] [#x2907 #x6170] [#xecdd #x4775] [#x619f #x1510] + [#x13cc #xa830] [#xeb61 #xbd96] [#x0334 #xfe1e] [#xaa03 #x63cf] + [#xb573 #x5c90] [#x4c70 #xa239] [#xd59e #x9e0b] [#xcbaa #xde14] + [#xeecc #x86bc] [#x6062 #x2ca7] [#x9cab #x5cab] [#xb2f3 #x846e] + [#x648b #x1eaf] [#x19bd #xf0ca] [#xa023 #x69b9] [#x655a #xbb50] + [#x4068 #x5a32] [#x3c2a #xb4b3] [#x319e #xe9d5] [#xc021 #xb8f7] + [#x9b54 #x0b19] [#x875f #xa099] [#x95f7 #x997e] [#x623d #x7da8] + [#xf837 #x889a] [#x97e3 #x2d77] [#x11ed #x935f] [#x1668 #x1281] + [#x0e35 #x8829] [#xc7e6 #x1fd6] [#x96de #xdfa1] [#x7858 #xba99] + [#x57f5 #x84a5] [#x1b22 #x7263] [#x9b83 #xc3ff] [#x1ac2 #x4696] + [#xcdb3 #x0aeb] [#x532e #x3054] [#x8fd9 #x48e4] [#x6dbc #x3128] + [#x58eb #xf2ef] [#x34c6 #xffea] [#xfe28 #xed61] [#xee7c #x3c73] + [#x5d4a #x14d9] [#xe864 #xb7e3] [#x4210 #x5d14] [#x203e #x13e0] + [#x45ee #xe2b6] [#xa3aa #xabea] [#xdb6c #x4f15] [#xfacb #x4fd0] + [#xc742 #xf442] [#xef6a #xbbb5] [#x654f #x3b1d] [#x41cd #x2105] + [#xd81e #x799e] [#x8685 #x4dc7] [#xe44b #x476a] [#x3d81 #x6250] + [#xcf62 #xa1f2] [#x5b8d #x2646] [#xfc88 #x83a0] [#xc1c7 #xb6a3] + [#x7f15 #x24c3] [#x69cb #x7492] [#x4784 #x8a0b] [#x5692 #xb285] + [#x095b #xbf00] [#xad19 #x489d] [#x1462 #xb174] [#x2382 #x0e00] + [#x5842 #x8d2a] [#x0c55 #xf5ea] [#x1dad #xf43e] [#x233f #x7061] + [#x3372 #xf092] [#x8d93 #x7e41] [#xd65f #xecf1] [#x6c22 #x3bdb] + [#x7cde #x3759] [#xcbee #x7460] [#x4085 #xf2a7] [#xce77 #x326e] + [#xa607 #x8084] [#x19f8 #x509e] [#xe8ef #xd855] [#x61d9 #x9735] + [#xa969 #xa7aa] [#xc50c #x06c2] [#x5a04 #xabfc] [#x800b #xcadc] + [#x9e44 #x7a2e] [#xc345 #x3484] [#xfdd5 #x6705] [#x0e1e #x9ec9] + [#xdb73 #xdbd3] [#x1055 #x88cd] [#x675f #xda79] [#xe367 #x4340] + [#xc5c4 #x3465] [#x713e #x38d8] [#x3d28 #xf89e] [#xf16d #xff20] + [#x153e #x21e7] [#x8fb0 #x3d4a] [#xe6e3 #x9f2b] [#xdb83 #xadf7] + ] + [ + [#xe93d #x5a68] [#x9481 #x40f7] [#xf64c #x261c] [#x9469 #x2934] + [#x4115 #x20f7] [#x7602 #xd4f7] [#xbcf4 #x6b2e] [#xd4a2 #x0068] + [#xd408 #x2471] [#x3320 #xf46a] [#x43b7 #xd4b7] [#x5000 #x61af] + [#x1e39 #xf62e] [#x9724 #x4546] [#x1421 #x4f74] [#xbf8b #x8840] + [#x4d95 #xfc1d] [#x96b5 #x91af] [#x70f4 #xddd3] [#x66a0 #x2f45] + [#xbfbc #x09ec] [#x03bd #x9785] [#x7fac #x6dd0] [#x31cb #x8504] + [#x96eb #x27b3] [#x55fd #x3941] [#xda25 #x47e6] [#xabca #x0a9a] + [#x2850 #x7825] [#x5304 #x29f4] [#x0a2c #x86da] [#xe9b6 #x6dfb] + [#x68dc #x1462] [#xd748 #x6900] [#x680e #xc0a4] [#x27a1 #x8dee] + [#x4f3f #xfea2] [#xe887 #xad8c] [#xb58c #xe006] [#x7af4 #xd6b6] + [#xaace #x1e7c] [#xd337 #x5fec] [#xce78 #xa399] [#x406b #x2a42] + [#x20fe #x9e35] [#xd9f3 #x85b9] [#xee39 #xd7ab] [#x3b12 #x4e8b] + [#x1dc9 #xfaf7] [#x4b6d #x1856] [#x26a3 #x6631] [#xeae3 #x97b2] + [#x3a6e #xfa74] [#xdd5b #x4332] [#x6841 #xe7f7] [#xca78 #x20fb] + [#xfb0a #xf54e] [#xd8fe #xb397] [#x4540 #x56ac] [#xba48 #x9527] + [#x5553 #x3a3a] [#x2083 #x8d87] [#xfe6b #xa9b7] [#xd096 #x954b] + [#x55a8 #x67bc] [#xa115 #x9a58] [#xcca9 #x2963] [#x99e1 #xdb33] + [#xa62a #x4a56] [#x3f31 #x25f9] [#x5ef4 #x7e1c] [#x9029 #x317c] + [#xfdf8 #xe802] [#x0427 #x2f70] [#x80bb #x155c] [#x0528 #x2ce3] + [#x95c1 #x1548] [#xe4c6 #x6d22] [#x48c1 #x133f] [#xc70f #x86dc] + [#x07f9 #xc9ee] [#x4104 #x1f0f] [#x4047 #x79a4] [#x5d88 #x6e17] + [#x325f #x51eb] [#xd59b #xc0d1] [#xf2bc #xc18f] [#x4111 #x3564] + [#x257b #x7834] [#x602a #x9c60] [#xdff8 #xe8a3] [#x1f63 #x6c1b] + [#x0e12 #xb4c2] [#x02e1 #x329e] [#xaf66 #x4fd1] [#xcad1 #x8115] + [#x6b23 #x95e0] [#x333e #x92e1] [#x3b24 #x0b62] [#xeebe #xb922] + [#x85b2 #xa20e] [#xe6ba #x0d99] [#xde72 #x0c8c] [#x2da2 #xf728] + [#xd012 #x7845] [#x95b7 #x94fd] [#x647d #x0862] [#xe7cc #xf5f0] + [#x5449 #xa36f] [#x877d #x48fa] [#xc39d #xfd27] [#xf33e #x8d1e] + [#x0a47 #x6341] [#x992e #xff74] [#x3a6f #x6eab] [#xf4f8 #xfd37] + [#xa812 #xdc60] [#xa1eb #xddf8] [#x991b #xe14c] [#xdb6e #x6b0d] + [#xc67b #x5510] [#x6d67 #x2c37] [#x2765 #xd43b] [#xdcd0 #xe804] + [#xf129 #x0dc7] [#xcc00 #xffa3] [#xb539 #x0f92] [#x690f #xed0b] + [#x667b #x9ffb] [#xcedb #x7d9c] [#xa091 #xcf0b] [#xd915 #x5ea3] + [#xbb13 #x2f88] [#x515b #xad24] [#x7b94 #x79bf] [#x763b #xd6eb] + [#x3739 #x2eb3] [#xcc11 #x5979] [#x8026 #xe297] [#xf42e #x312d] + [#x6842 #xada7] [#xc66a #x2b3b] [#x1275 #x4ccc] [#x782e #xf11c] + [#x6a12 #x4237] [#xb792 #x51e7] [#x06a1 #xbbe6] [#x4bfb #x6350] + [#x1a6b #x1018] [#x11ca #xedfa] [#x3d25 #xbdd8] [#xe2e1 #xc3c9] + [#x4442 #x1659] [#x0a12 #x1386] [#xd90c #xec6e] [#xd5ab #xea2a] + [#x64af #x674e] [#xda86 #xa85f] [#xbebf #xe988] [#x64e4 #xc3fe] + [#x9dbc #x8057] [#xf0f7 #xc086] [#x6078 #x7bf8] [#x6003 #x604d] + [#xd1fd #x8346] [#xf638 #x1fb0] [#x7745 #xae04] [#xd736 #xfccc] + [#x8342 #x6b33] [#xf01e #xab71] [#xb080 #x4187] [#x3c00 #x5e5f] + [#x77a0 #x57be] [#xbde8 #xae24] [#x5546 #x4299] [#xbf58 #x2e61] + [#x4e58 #xf48f] [#xf2dd #xfda2] [#xf474 #xef38] [#x8789 #xbdc2] + [#x5366 #xf9c3] [#xc8b3 #x8e74] [#xb475 #xf255] [#x46fc #xd9b9] + [#x7aeb #x2661] [#x8b1d #xdf84] [#x846a #x0e79] [#x915f #x95e2] + [#x466e #x598e] [#x20b4 #x5770] [#x8cd5 #x5591] [#xc902 #xde4c] + [#xb90b #xace1] [#xbb82 #x05d0] [#x11a8 #x6248] [#x7574 #xa99e] + [#xb77f #x19b6] [#xe0a9 #xdc09] [#x662d #x09a1] [#xc432 #x4633] + [#xe85a #x1f02] [#x09f0 #xbe8c] [#x4a99 #xa025] [#x1d6e #xfe10] + [#x1ab9 #x3d1d] [#x0ba5 #xa4df] [#xa186 #xf20f] [#x2868 #xf169] + [#xdcb7 #xda83] [#x5739 #x06fe] [#xa1e2 #xce9b] [#x4fcd #x7f52] + [#x5011 #x5e01] [#xa706 #x83fa] [#xa002 #xb5c4] [#x0de6 #xd027] + [#x9af8 #x8c27] [#x773f #x8641] [#xc360 #x4c06] [#x61a8 #x06b5] + [#xf017 #x7a28] [#xc0f5 #x86e0] [#x0060 #x58aa] [#x30dc #x7d62] + [#x11e6 #x9ed7] [#x2338 #xea63] [#x53c2 #xdd94] [#xc2c2 #x1634] + [#xbbcb #xee56] [#x90bc #xb6de] [#xebfc #x7da1] [#xce59 #x1d76] + [#x6f05 #xe409] [#x4b7c #x0188] [#x3972 #x0a3d] [#x7c92 #x7c24] + [#x86e3 #x725f] [#x724d #x9db9] [#x1ac1 #x5bb4] [#xd39e #xb8fc] + [#xed54 #x5578] [#x08fc #xa5b5] [#xd83d #x7cd3] [#x4dad #x0fc4] + [#x1e50 #xef5e] [#xb161 #xe6f8] [#xa285 #x14d9] [#x6c51 #x133c] + [#x6fd5 #xc7e7] [#x56e1 #x4ec4] [#x362a #xbfce] [#xddc6 #xc837] + [#xd79a #x3234] [#x9263 #x8212] [#x670e #xfa8e] [#x4060 #x00e0] + ] + [ + [#x3a39 #xce37] [#xd3fa #xf5cf] [#xabc2 #x7737] [#x5ac5 #x2d1b] + [#x5cb0 #x679e] [#x4fa3 #x3742] [#xd382 #x2740] [#x99bc #x9bbe] + [#xd511 #x8e9d] [#xbf0f #x7315] [#xd62d #x1c7e] [#xc700 #xc47b] + [#xb78c #x1b6b] [#x21a1 #x9045] [#xb26e #xb1be] [#x6a36 #x6eb4] + [#x5748 #xab2f] [#xbc94 #x6e79] [#xc6a3 #x76d2] [#x6549 #xc2c8] + [#x530f #xf8ee] [#x468d #xde7d] [#xd573 #x0a1d] [#x4cd0 #x4dc6] + [#x2939 #xbbdb] [#xa9ba #x4650] [#xac95 #x26e8] [#xbe5e #xe304] + [#xa1fa #xd5f0] [#x6a2d #x519a] [#x63ef #x8ce2] [#x9a86 #xee22] + [#xc089 #xc2b8] [#x4324 #x2ef6] [#xa51e #x03aa] [#x9cf2 #xd0a4] + [#x83c0 #x61ba] [#x9be9 #x6a4d] [#x8fe5 #x1550] [#xba64 #x5bd6] + [#x2826 #xa2f9] [#xa73a #x3ae1] [#x4ba9 #x9586] [#xef55 #x62e9] + [#xc72f #xefd3] [#xf752 #xf7da] [#x3f04 #x6f69] [#x77fa #x0a59] + [#x80e4 #xa915] [#x87b0 #x8601] [#x9b09 #xe6ad] [#x3b3e #xe593] + [#xe990 #xfd5a] [#x9e34 #xd797] [#x2cf0 #xb7d9] [#x022b #x8b51] + [#x96d5 #xac3a] [#x017d #xa67d] [#xd1cf #x3ed6] [#x7c7d #x2d28] + [#x1f9f #x25cf] [#xadf2 #xb89b] [#x5ad6 #xb472] [#x5a88 #xf54c] + [#xe029 #xac71] [#xe019 #xa5e6] [#x47b0 #xacfd] [#xed93 #xfa9b] + [#xe8d3 #xc48d] [#x283b #x57cc] [#xf8d5 #x6629] [#x7913 #x2e28] + [#x785f #x0191] [#xed75 #x6055] [#xf796 #x0e44] [#xe3d3 #x5e8c] + [#x1505 #x6dd4] [#x88f4 #x6dba] [#x03a1 #x6125] [#x0564 #xf0bd] + [#xc3eb #x9e15] [#x3c90 #x57a2] [#x9727 #x1aec] [#xa93a #x072a] + [#x1b3f #x6d9b] [#x1e63 #x21f5] [#xf59c #x66fb] [#x26dc #xf319] + [#x7533 #xd928] [#xb155 #xfdf5] [#x0356 #x3482] [#x8aba #x3cbb] + [#x2851 #x7711] [#xc20a #xd9f8] [#xabcc #x5167] [#xccad #x925f] + [#x4de8 #x1751] [#x3830 #xdc8e] [#x379d #x5862] [#x9320 #xf991] + [#xea7a #x90c2] [#xfb3e #x7bce] [#x5121 #xce64] [#x774f #xbe32] + [#xa8b6 #xe37e] [#xc329 #x3d46] [#x48de #x5369] [#x6413 #xe680] + [#xa2ae #x0810] [#xdd6d #xb224] [#x6985 #x2dfd] [#x0907 #x2166] + [#xb39a #x460a] [#x6445 #xc0dd] [#x586c #xdecf] [#x1c20 #xc8ae] + [#x5bbe #xf7dd] [#x1b58 #x8d40] [#xccd2 #x017f] [#x6bb4 #xe3bb] + [#xdda2 #x6a7e] [#x3a59 #xff45] [#x3e35 #x0a44] [#xbcb4 #xcdd5] + [#x72ea #xcea8] [#xfa64 #x84bb] [#x8d66 #x12ae] [#xbf3c #x6f47] + [#xd29b #xe463] [#x542f #x5d9e] [#xaec2 #x771b] [#xf64e #x6370] + [#x740e #x0d8d] [#xe75b #x1357] [#xf872 #x1671] [#xaf53 #x7d5d] + [#x4040 #xcb08] [#x4eb4 #xe2cc] [#x34d2 #x466a] [#x0115 #xaf84] + [#xe1b0 #x0428] [#x9598 #x3a1d] [#x06b8 #x9fb4] [#xce6e #xa048] + [#x6f3f #x3b82] [#x3520 #xab82] [#x011a #x1d4b] [#x2772 #x27f8] + [#x6115 #x60b1] [#xe793 #x3fdc] [#xbb3a #x792b] [#x3445 #x25bd] + [#xa088 #x39e1] [#x51ce #x794b] [#x2f32 #xc9b7] [#xa01f #xbac9] + [#xe01c #xc87e] [#xbcc7 #xd1f6] [#xcf01 #x11c3] [#xa1e8 #xaac7] + [#x1a90 #x8749] [#xd44f #xbd9a] [#xd0da #xdecb] [#xd50a #xda38] + [#x0339 #xc32a] [#xc691 #x3667] [#x8df9 #x317c] [#xe0b1 #x2b4f] + [#xf79e #x59b7] [#x43f5 #xbb3a] [#xf2d5 #x19ff] [#x27d9 #x459c] + [#xbf97 #x222c] [#x15e6 #xfc2a] [#x0f91 #xfc71] [#x9b94 #x1525] + [#xfae5 #x9361] [#xceb6 #x9ceb] [#xc2a8 #x6459] [#x12ba #xa8d1] + [#xb6c1 #x075e] [#xe305 #x6a0c] [#x10d2 #x5065] [#xcb03 #xa442] + [#xe0ec #x6e0e] [#x1698 #xdb3b] [#x4c98 #xa0be] [#x3278 #xe964] + [#x9f1f #x9532] [#xe0d3 #x92df] [#xd3a0 #x342b] [#x8971 #xf21e] + [#x1b0a #x7441] [#x4ba3 #x348c] [#xc5be #x7120] [#xc376 #x32d8] + [#xdf35 #x9f8d] [#x9b99 #x2f2e] [#xe60b #x6f47] [#x0fe3 #xf11d] + [#xe54c #xda54] [#x1eda #xd891] [#xce62 #x79cf] [#xcd3e #x7e6f] + [#x1618 #xb166] [#xfd2c #x1d05] [#x848f #xd2c5] [#xf6fb #x2299] + [#xf523 #xf357] [#xa632 #x7623] [#x93a8 #x3531] [#x56cc #xcd02] + [#xacf0 #x8162] [#x5a75 #xebb5] [#x6e16 #x3697] [#x88d2 #x73cc] + [#xde96 #x6292] [#x81b9 #x49d0] [#x4c50 #x901b] [#x71c6 #x5614] + [#xe6c6 #xc7bd] [#x327a #x140a] [#x45e1 #xd006] [#xc3f2 #x7b9a] + [#xc9aa #x53fd] [#x62a8 #x0f00] [#xbb25 #xbfe2] [#x35bd #xd2f6] + [#x7112 #x6905] [#xb204 #x0222] [#xb6cb #xcf7c] [#xcd76 #x9c2b] + [#x5311 #x3ec0] [#x1640 #xe3d3] [#x38ab #xbd60] [#x2547 #xadf0] + [#xba38 #x209c] [#xf746 #xce76] [#x77af #xa1c5] [#x2075 #x6060] + [#x85cb #xfe4e] [#x8ae8 #x8dd8] [#x7aaa #xf9b0] [#x4cf9 #xaa7e] + [#x1948 #xc25c] [#x02fb #x8a8c] [#x01c3 #x6ae4] [#xd6eb #xe1f9] + [#x90d4 #xf869] [#xa65c #xdea0] [#x3f09 #x252d] [#xc208 #xe69f] + [#xb74e #x6132] [#xce77 #xe25b] [#x578f #xdfe3] [#x3ac3 #x72e6] + ]]) + +(defconst blowfish-p-array-inits + [ + [#x243f #x6a88] [#x85a3 #x08d3] [#x1319 #x8a2e] [#x0370 #x7344] + [#xa409 #x3822] [#x299f #x31d0] [#x082e #xfa98] [#xec4e #x6c89] + [#x4528 #x21e6] [#x38d0 #x1377] [#xbe54 #x66cf] [#x34e9 #x0c6c] + [#xc0ac #x29b7] [#xc97c #x50dd] [#x3f84 #xd5b5] [#xb547 #x0917] + [#x9216 #xd5d9] [#x8979 #xfb1b] + ]) + +(defun blowfish-generate-keys (key) + "given a key vector \(an even number of 16-bit integers\), returns +the p-array and s-boxes for Blowfish encryption using that key, as a +pair: \(P-array . S-boxes\)." + (let ((s-boxes (vector (make-vector 256 nil) + (make-vector 256 nil) + (make-vector 256 nil) + (make-vector 256 nil))) + (p-array (make-vector 18 nil))) + ;; copy the initial values into the s-boxes + (dotimes (s 4) + (let ((s-box (aref s-boxes s)) + (inits (aref blowfish-s-box-inits s))) + (dotimes (idx 256) + (aset s-box idx (copy-seq (aref inits idx)))))) + ;; copy the initial values into the p-array + (dotimes (idx 18) + (aset p-array idx (copy-seq (aref blowfish-p-array-inits idx)))) + + ;; mix the key into the P-array + (let ((keylen (length key))) + (assert (and (>= keylen 2) (evenp keylen)) nil + "Blowfish key must be a positive multiple of 2 elements long.") + + (dotimes (idx 18) + (let* ((keyidx (mod (* 2 idx) keylen)) + (keyval (vector (aref key keyidx) + (aref key (1+ keyidx)))) + (p-entry (aref p-array idx))) + (blowfish-xor p-entry keyval p-entry) + ;; clean up + (fillarray keyval 0)))) + + ;; begin the iterated filling of the P-array and S-boxes + (let ((data (vector 0 0 0 0))) + ;; fill the P-array + (do ((idx 0 (+ idx 2))) + ((= idx 18)) + ;; encipher data w/ the current P-array and S-boxes + (blowfish-cipher-block data p-array s-boxes) + ;; replace the next two P-array elements with the new data + (let ((Pa (aref p-array idx)) + (Pb (aref p-array (1+ idx)))) + (aset Pa 0 (aref data 0)) + (aset Pa 1 (aref data 1)) + (aset Pb 0 (aref data 2)) + (aset Pb 1 (aref data 3)))) + + ;; fill the S-boxes + (dotimes (s 4) + (do ((idx 0 (+ idx 2)) + (s-box (aref s-boxes s))) + ((= idx 256)) + ;; encipher data w/ the current P-array and S-boxes + (blowfish-cipher-block data p-array s-boxes) + ;; replace the next two S-box elements with the new data + (let ((Sa (aref s-box idx)) + (Sb (aref s-box (1+ idx)))) + (aset Sa 0 (aref data 0)) + (aset Sa 1 (aref data 1)) + (aset Sb 0 (aref data 2)) + (aset Sb 1 (aref data 3))))) + + ;; clean up + (fillarray data 0)) + + ;; return the result + (cons p-array s-boxes))) diff --git a/xemacs-packages/lisp/ecrypto/blowfish.elc b/xemacs-packages/lisp/ecrypto/blowfish.elc new file mode 100644 index 0000000000000000000000000000000000000000..e2c380440b3f2b52e69af90c166701c4a94527fb GIT binary patch literal 18535 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/custom-load.el b/xemacs-packages/lisp/ecrypto/custom-load.el new file mode 100644 index 00000000..0046c57a --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/custom-load.el @@ -0,0 +1,14 @@ +;;; custom-load.el --- automatically extracted custom dependencies + +;;; Code: + +(autoload 'custom-add-loads "cus-load") + +(custom-add-loads 'extensions '("sha1")) +(custom-add-loads 'password '("password")) +(custom-add-loads 'rijndael '("rijndael")) +(custom-add-loads 'encrypt '("password" "encrypt")) +(custom-add-loads 'applications '("encrypt")) +(custom-add-loads 'sha1 '("sha1")) + +;;; custom-load.el ends here diff --git a/xemacs-packages/lisp/ecrypto/custom-load.elc b/xemacs-packages/lisp/ecrypto/custom-load.elc new file mode 100644 index 0000000000000000000000000000000000000000..22c964607299aea5cc5443755f840cd99e736ca4 GIT binary patch literal 837 zcmZWnOOMkq5bl+n`2izeHaXr4qI9p21s6>xjSE_Ys)~kFm2-%jNJ6~S&o-&sk z%GPwnUCEi<8m~(>IIsI$YT6cD#=MaUSC~hjd{Y;9AvM&q4(e$Je)}HmkDtN* z`h7{>5O_uhufzRg?zjuIZKJLOf=F};&KmbJEQEuUxQ^B&14EtLXp6HZdlykFUaFRI liRj)%l&iRKe^Y_%Ks=_#NWtP31cAdrkV0Tod=7WA= shift len) + (< shift 0)) + (setq shift (mod shift len))) + (do ((out-idx 0 (1+ out-idx)) + (in-idx shift (1+ in-idx))) + ((= in-idx len)) + (aset outvec out-idx (aref vec in-idx))) + (do ((out-idx (- len shift) (1+ out-idx)) + (in-idx 0 (1+ in-idx))) + ((= in-idx shift) outvec) + (aset outvec out-idx (aref vec in-idx))))) + + +(defconst des-key-shifts [1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1]) + +(defun des-compute-subkeys (key) + "computes the 16 48-bit subkeys from a 64-bit key" + (let* ((subkeys (make-vector 16 [])) + (PC1 (des-PC1 key)) + (C (subseq PC1 0 28)) + (D (subseq PC1 28 56))) + ;; clean up + (fillarray PC1 nil) + ;; compute subkeys + (dotimes (count 16) + (let* ((new-C (des-<<< C (aref des-key-shifts count))) + (new-D (des-<<< D (aref des-key-shifts count))) + (CD (vconcat new-C new-D))) + (aset subkeys count (des-PC2 CD)) + ;; clean up + (fillarray C nil) + (fillarray D nil) + ;; replace old with new + (setq C new-C) + (setq D new-D))) + (fillarray C nil) + (fillarray D nil) + subkeys)) + + + +(defconst des-E-vals [31 0 1 2 3 4 3 4 5 6 7 8 7 8 9 10 11 12 11 12 13 14 15 16 15 16 17 18 19 20 19 20 21 22 23 24 23 24 25 26 27 28 27 28 29 30 31 0]) + +(defun des-E (vec) + "perform the Expansion function on a 32-bit vector" + (assert (= (length vec) 32) nil + "des-E: vec must be 32 bits long") + (des-permute vec des-E-vals)) + +(defun des-xor-in-place (vec1 vec2) + "XOR two bit vectors together, storing in the first" + (let ((len (length vec1))) + (assert (= len (length vec2)) nil + "des-xor: vec1 and vec2 must be of same length") + (dotimes (idx len vec1) + (aset vec1 idx (not (eq (aref vec1 idx) + (aref vec2 idx))))))) + +(defun des-integer-to-bitvec (val) + "converts an integer to a 4-bit bit vector (used to construct S-boxes)" + (let ((out (make-vector 4 nil))) + (dotimes (shift 4 out) + (when (= 1 (logand 1 (ash val (- shift 3)))) + (aset out shift t))))) + + +(defconst des-S-boxes-vals + [[[14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7] + [ 0 15 7 4 14 2 13 1 10 6 12 11 9 5 3 8] + [ 4 1 14 8 13 6 2 11 15 12 9 7 3 10 5 0] + [15 12 8 2 4 9 1 7 5 11 3 14 10 0 6 13]] + + [[15 1 8 14 6 11 3 4 9 7 2 13 12 0 5 10] + [ 3 13 4 7 15 2 8 14 12 0 1 10 6 9 11 5] + [ 0 14 7 11 10 4 13 1 5 8 12 6 9 3 2 15] + [13 8 10 1 3 15 4 2 11 6 7 12 0 5 14 9]] + + [[10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8] + [13 7 0 9 3 4 6 10 2 8 5 14 12 11 15 1] + [13 6 4 9 8 15 3 0 11 1 2 12 5 10 14 7] + [ 1 10 13 0 6 9 8 7 4 15 14 3 11 5 2 12]] + + [[ 7 13 14 3 0 6 9 10 1 2 8 5 11 12 4 15] + [13 8 11 5 6 15 0 3 4 7 2 12 1 10 14 9] + [10 6 9 0 12 11 7 13 15 1 3 14 5 2 8 4] + [ 3 15 0 6 10 1 13 8 9 4 5 11 12 7 2 14]] + + [[ 2 12 4 1 7 10 11 6 8 5 3 15 13 0 14 9] + [14 11 2 12 4 7 13 1 5 0 15 10 3 9 8 6] + [ 4 2 1 11 10 13 7 8 15 9 12 5 6 3 0 14] + [11 8 12 7 1 14 2 13 6 15 0 9 10 4 5 3]] + + [[12 1 10 15 9 2 6 8 0 13 3 4 14 7 5 11] + [10 15 4 2 7 12 9 5 6 1 13 14 0 11 3 8] + [ 9 14 15 5 2 8 12 3 7 0 4 10 1 13 11 6] + [ 4 3 2 12 9 5 15 10 11 14 1 7 6 0 8 13]] + + [[ 4 11 2 14 15 0 8 13 3 12 9 7 5 10 6 1] + [13 0 11 7 4 9 1 10 14 3 5 12 2 15 8 6] + [ 1 4 11 13 12 3 7 14 10 15 6 8 0 5 9 2] + [ 6 11 13 8 1 4 10 7 9 5 0 15 14 2 3 12]] + + [[13 2 8 4 6 15 11 1 10 9 3 14 5 0 12 7] + [ 1 15 13 8 10 3 7 4 12 5 6 11 0 14 9 2] + [ 7 11 4 1 9 12 14 2 0 6 10 13 15 3 5 8] + [ 2 1 14 7 4 10 8 13 15 12 9 0 3 5 6 11]]]) + +(defconst des-S-boxes (map 'vector + #'(lambda (x) + (map 'vector + #'(lambda (y) + (map 'vector + #'des-integer-to-bitvec + y)) + x)) + des-S-boxes-vals)) + +(defun des-S (vec) + "do the S substitution on a 48-bit vector, returning a 32-bit vector" + (let ((temp-vecs (make-vector 8 nil))) + (do ((Sidx 0 (1+ Sidx)) + (bitidx 0 (+ bitidx 6))) + ((= Sidx 8)) + (let ((val1 (+ (if (aref vec (+ bitidx 0)) 2 0) + (if (aref vec (+ bitidx 5)) 1 0))) + (val2 (+ (if (aref vec (+ bitidx 1)) 8 0) + (if (aref vec (+ bitidx 2)) 4 0) + (if (aref vec (+ bitidx 3)) 2 0) + (if (aref vec (+ bitidx 4)) 1 0)))) + (aset temp-vecs Sidx (aref (aref (aref des-S-boxes Sidx) + val1) + val2)))) + (prog1 + (apply #'vconcat (coerce temp-vecs 'list)) + ;; clean up + (fillarray temp-vecs nil)))) + +(defconst des-P-vals [15 6 19 20 28 11 27 16 0 14 22 25 4 17 30 9 1 7 23 13 31 26 2 8 18 12 29 5 21 10 3 24]) + +(defun des-P (vec) + "perform the P permutation on a 32-bit vector" + (assert (= (length vec) 32) nil + "des-P: vec must be 32 bits long") + (des-permute vec des-P-vals)) + +(defun des-f (vec key) + "perform the des f() function on 32-bit VEC and 48-bit KEY" + (let* ((E-vec (des-E vec)) + (S-vec (des-S (des-xor-in-place E-vec key))) + (P-vec (des-P S-vec))) + (prog1 + P-vec + ;; clean up + (fillarray E-vec nil) + (fillarray S-vec nil)))) + +(defconst des-IP-vals [57 49 41 33 25 17 9 1 59 51 43 35 27 19 11 3 61 53 45 37 29 21 13 5 63 55 47 39 31 23 15 7 56 48 40 32 24 16 8 0 58 50 42 34 26 18 10 2 60 52 44 36 28 20 12 4 62 54 46 38 30 22 14 6]) + +(defun des-IP (vec) + "perform the Initial Permutation on a 64-bit data vector" + (assert (= (length vec) 64) nil + "des-IP: vec must be 64 bits long") + (des-permute vec des-IP-vals)) + + +(defconst des-IP-inv-vals [39 7 47 15 55 23 63 31 38 6 46 14 54 22 62 30 37 5 45 13 53 21 61 29 36 4 44 12 52 20 60 28 35 3 43 11 51 19 59 27 34 2 42 10 50 18 58 26 33 1 41 9 49 17 57 25 32 0 40 8 48 16 56 24]) + +(defun des-IP-inv (vec) + "perform the inverse of the Initial Permutation on a 64-bit data vector" + (assert (= (length vec) 64) nil + "des-IP-inv: vec must be 64 bits long") + (des-permute vec des-IP-inv-vals)) + +(defun des-cipher-block (vec subkeys &optional reverse) + "perform the DES cipher on a 64-bit VEC using SUBKEYS. +if optional third arg REVERSE is true, decrypts." + (let* ((IP (des-IP vec)) + (L (subseq IP 0 32)) + (R (subseq IP 32 64))) + ;; clean up + (fillarray IP nil) + + (dotimes (count 16) + (let ((f-R (des-f R (aref subkeys (if reverse (- 15 count) count)))) + (old-R R) + (old-L L)) + (setq L old-R) + (setq R (des-xor-in-place old-L f-R)) + ;; clean up + (fillarray f-R nil))) + + (let ((RL (vconcat R L))) + (prog1 + (des-IP-inv RL) + ;; clean up + (fillarray RL nil) + (fillarray R nil) + (fillarray L nil))))) + +(defun des-triple-des (data subkeys1 subkeys2 subkeys3 &optional reverse) + "perform the triple-DES encryption on DATA with three sets of subkeys. +if optional fifth arg REVERSE is true, decrypts." + (if (not reverse) + (let* ((E1 (des-cipher-block data subkeys1)) + (E2 (des-cipher-block E1 subkeys2 t)) + (E3 (des-cipher-block E2 subkeys3))) + ;; clean up + (fillarray E1 nil) + (fillarray E2 nil) + E3) + + (let* ((D1 (des-cipher-block data subkeys3 t)) + (D2 (des-cipher-block D1 subkeys2)) + (D3 (des-cipher-block D2 subkeys1 t))) + ;; clean up + (fillarray D1 nil) + (fillarray D2 nil) + D3))) diff --git a/xemacs-packages/lisp/ecrypto/des.elc b/xemacs-packages/lisp/ecrypto/des.elc new file mode 100644 index 0000000000000000000000000000000000000000..a83e543b355598185b043e4529115c0ef8a8638b GIT binary patch literal 8486 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 +;; Created: 2003/01/24 +;; Keywords: files + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 module addresses data encryption. Page breaks are used for +;;; grouping declarations and documentation relating to each +;;; particular aspect. + +;;; Code: + +;; autoload password +(eval-and-compile + (autoload 'password-read "password")) + +(defgroup encrypt '((password-cache custom-variable) + (password-cache-expiry custom-variable)) + "File encryption configuration." + :group 'applications) + +(defcustom encrypt-file-alist nil + "List of file names or regexes matched with encryptions. +Format example: + '((\"beta\" + (gpg \"AES\")) + (\"/home/tzz/alpha\" + (encrypt-xor \"Semi-Secret\")))" + + :type '(repeat + (list :tag "Encryption entry" + (radio :tag "What to encrypt" + (file :tag "Filename") + (regexp :tag "Regular expression match")) + (radio :tag "How to encrypt it" + (list + :tag "GPG Encryption" + (const :tag "GPG Program" gpg) + (radio :tag "Choose a cipher" + (const :tag "3DES Encryption" "3DES") + (const :tag "CAST5 Encryption" "CAST5") + (const :tag "Blowfish Encryption" "BLOWFISH") + (const :tag "AES Encryption" "AES") + (const :tag "AES192 Encryption" "AES192") + (const :tag "AES256 Encryption" "AES256") + (const :tag "Twofish Encryption" "TWOFISH") + (string :tag "Cipher Name"))) + (list + :tag "Built-in simple XOR" + (const :tag "XOR Encryption" encrypt-xor) + (string :tag "XOR Cipher Value (seed value)"))))) + :group 'encrypt) + +;; TODO: now, load gencrypt.el and if successful, modify the +;; custom-type of encrypt-file-alist to add the gencrypt.el options + +;; (plist-get (symbol-plist 'encrypt-file-alist) 'custom-type) +;; then use plist-put + +(defcustom encrypt-gpg-path (executable-find "gpg") + "Path to the GPG program." + :type '(radio + (file :tag "Location of the GPG executable") + (const :tag "GPG is not installed" nil)) + :group 'encrypt) + +(defvar encrypt-temp-prefix "encrypt" + "Prefix for temporary filenames") + +;;;###autoload +(defun encrypt-find-model (filename) + "Given a filename, find a encrypt-file-alist entry" + (dolist (entry encrypt-file-alist) + (let ((match (nth 0 entry)) + (model (nth 1 entry))) + (when (or (eq match filename) + (string-match match filename)) + (return model))))) + +;;;###autoload +(defun encrypt-insert-file-contents (file &optional model) + "Decrypt FILE into the current buffer." + (interactive "fFile to insert: ") + (let* ((model (or model (encrypt-find-model file))) + (method (nth 0 model)) + (cipher (nth 1 model)) + (password-key (format "encrypt-password-%s-%s %s" + (symbol-name method) cipher file)) + (passphrase + (password-read-and-add + (format "%s password for cipher %s? " + (symbol-name method) cipher) + password-key)) + (buffer-file-coding-system 'binary) + (coding-system-for-read 'binary) + outdata) + + ;; note we only insert-file-contents if the method is known to be valid + (cond + ((eq method 'gpg) + (insert-file-contents file) + (setq outdata (encrypt-gpg-decode-buffer passphrase cipher))) + ((eq method 'encrypt-xor) + (insert-file-contents file) + (setq outdata (encrypt-xor-decode-buffer passphrase cipher)))) + + (if outdata + (progn + (gnus-message 9 "%s was decrypted with %s (cipher %s)" + file (symbol-name method) cipher) + (delete-region (point-min) (point-max)) + (goto-char (point-min)) + (insert outdata)) + ;; the decryption failed, alas + (password-cache-remove password-key) + (gnus-error 5 "%s was NOT decrypted with %s (cipher %s)" + file (symbol-name method) cipher)))) + +(defun encrypt-get-file-contents (file &optional model) + "Decrypt FILE and return the contents." + (interactive "fFile to decrypt: ") + (with-temp-buffer + (encrypt-insert-file-contents file model) + (buffer-string))) + +(defun encrypt-put-file-contents (file data &optional model) + "Encrypt the DATA to FILE, then continue normally." + (with-temp-buffer + (insert data) + (encrypt-write-file-contents file model))) + +(defun encrypt-write-file-contents (file &optional model) + "Encrypt the current buffer to FILE, then continue normally." + (interactive "fFile to write: ") + (let* ((model (or model (encrypt-find-model file))) + (method (nth 0 model)) + (cipher (nth 1 model)) + (password-key (format "encrypt-password-%s-%s %s" + (symbol-name method) cipher file)) + (passphrase + (password-read + (format "%s password for cipher %s? " + (symbol-name method) cipher) + password-key)) + outdata) + + (cond + ((eq method 'gpg) + (setq outdata (encrypt-gpg-encode-buffer passphrase cipher))) + ((eq method 'encrypt-xor) + (setq outdata (encrypt-xor-encode-buffer passphrase cipher)))) + + (if outdata + (progn + (gnus-message 9 "%s was encrypted with %s (cipher %s)" + file (symbol-name method) cipher) + (delete-region (point-min) (point-max)) + (goto-char (point-min)) + (insert outdata) + ;; do not confirm overwrites + (write-file file nil)) + ;; the decryption failed, alas + (password-cache-remove password-key) + (gnus-error 5 "%s was NOT encrypted with %s (cipher %s)" + file (symbol-name method) cipher)))) + +(defun encrypt-xor-encode-buffer (passphrase cipher) + (encrypt-xor-process-buffer passphrase cipher t)) + +(defun encrypt-xor-decode-buffer (passphrase cipher) + (encrypt-xor-process-buffer passphrase cipher nil)) + +(defun encrypt-xor-process-buffer (passphrase + cipher + &optional encode) + "Given PASSPHRASE, xor-encode or decode the contents of the current buffer." + (let* ((bs (buffer-substring-no-properties (point-min) (point-max))) + ;; passphrase-sum is a simple additive checksum of the + ;; passphrase and the cipher + (passphrase-sum + (when (stringp passphrase) + (apply '+ (append cipher passphrase nil)))) + new-list) + + (with-temp-buffer + (if encode + (progn + (dolist (x (append bs nil)) + (setq new-list (cons (logxor x passphrase-sum) new-list))) + + (dolist (x new-list) + (insert (format "%d " x)))) + (progn + (setq new-list (reverse (split-string bs))) + (dolist (x new-list) + (setq x (string-to-number x)) + (insert (format "%c" (logxor x passphrase-sum)))))) + (buffer-substring-no-properties (point-min) (point-max))))) + +(defun encrypt-gpg-encode-buffer (passphrase cipher) + (encrypt-gpg-process-buffer passphrase cipher t)) + +(defun encrypt-gpg-decode-buffer (passphrase cipher) + (encrypt-gpg-process-buffer passphrase cipher nil)) + +(defun encrypt-gpg-process-buffer (passphrase + cipher + &optional encode) + "With PASSPHRASE, use GPG to encode or decode the current buffer." + (let* ((program encrypt-gpg-path) + (input (buffer-substring-no-properties (point-min) (point-max))) + (temp-maker (if (fboundp 'make-temp-file) + 'make-temp-file + 'make-temp-name)) + (temp-file (funcall temp-maker encrypt-temp-prefix)) + (default-enable-multibyte-characters nil) + (args `("--cipher-algo" ,cipher + "--status-fd" "2" + "--logger-fd" "2" + "--passphrase-fd" "0" + "--no-tty")) + exit-status exit-data) + + (when encode + (setq args + (append args + '("--symmetric" + "--armor")))) + + (if program + (with-temp-buffer + (when passphrase + (insert passphrase "\n")) + (insert input) + (setq exit-status + (apply #'call-process-region (point-min) (point-max) program + t `(t ,temp-file) nil args)) + (if (equal exit-status 0) + (setq exit-data + (buffer-substring-no-properties (point-min) (point-max))) + (with-temp-buffer + (when (file-exists-p temp-file) + (insert-file-contents temp-file)) + (gnus-error 5 (format "%s exited abnormally: '%s' [%s]" + program exit-status (buffer-string))))) + (delete-file temp-file)) + (gnus-error 5 "GPG is not installed.")) + exit-data)) + +(provide 'encrypt) +;;; encrypt.el ends here + +;; arch-tag: d907e4f1-71b5-42b1-a180-fc7b84ff0648 diff --git a/xemacs-packages/lisp/ecrypto/encrypt.elc b/xemacs-packages/lisp/ecrypto/encrypt.elc new file mode 100644 index 0000000000000000000000000000000000000000..e9fb48dde490f8ce4690ca461c08574897ecbe87 GIT binary patch literal 6743 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/hex-util.el b/xemacs-packages/lisp/ecrypto/hex-util.el new file mode 100644 index 00000000..1cc67c28 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/hex-util.el @@ -0,0 +1,75 @@ +;;; hex-util.el --- Functions to encode/decode hexadecimal string. + +;; Copyright (C) 1999, 2001, 2002, 2003, 2004, +;; 2005 Free Software Foundation, Inc. + +;; Author: Shuhei KOBAYASHI +;; Keywords: data + +;; This file is part of FLIM (Faithful Library about Internet Message). + +;; This program 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 program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;;; Code: + +(eval-when-compile + (defmacro hex-char-to-num (chr) + (` (let ((chr (, chr))) + (cond + ((and (<= ?a chr)(<= chr ?f)) (+ (- chr ?a) 10)) + ((and (<= ?A chr)(<= chr ?F)) (+ (- chr ?A) 10)) + ((and (<= ?0 chr)(<= chr ?9)) (- chr ?0)) + (t (error "Invalid hexadecimal digit `%c'" chr)))))) + (defmacro num-to-hex-char (num) + (` (aref "0123456789abcdef" (, num))))) + +(defun decode-hex-string (string) + "Decode hexadecimal STRING to octet string." + (let* ((len (length string)) + (dst (make-string (/ len 2) 0)) + (idx 0)(pos 0)) + (while (< pos len) +;;; logior and lsh are not byte-coded. +;;; (aset dst idx (logior (lsh (hex-char-to-num (aref string pos)) 4) +;;; (hex-char-to-num (aref string (1+ pos))))) + (aset dst idx (+ (* (hex-char-to-num (aref string pos)) 16) + (hex-char-to-num (aref string (1+ pos))))) + (setq idx (1+ idx) + pos (+ 2 pos))) + dst)) + +(defun encode-hex-string (string) + "Encode octet STRING to hexadecimal string." + (let* ((len (length string)) + (dst (make-string (* len 2) 0)) + (idx 0)(pos 0)) + (while (< pos len) +;;; logand and lsh are not byte-coded. +;;; (aset dst idx (num-to-hex-char (logand (lsh (aref string pos) -4) 15))) + (aset dst idx (num-to-hex-char (/ (aref string pos) 16))) + (setq idx (1+ idx)) +;;; (aset dst idx (num-to-hex-char (logand (aref string pos) 15))) + (aset dst idx (num-to-hex-char (% (aref string pos) 16))) + (setq idx (1+ idx) + pos (1+ pos))) + dst)) + +(provide 'hex-util) + +;;; arch-tag: fe8aaa79-6c86-400e-813f-5a8cc4cb3859 +;;; hex-util.el ends here diff --git a/xemacs-packages/lisp/ecrypto/hex-util.elc b/xemacs-packages/lisp/ecrypto/hex-util.elc new file mode 100644 index 0000000000000000000000000000000000000000..6ea28fd8a84e4ffadaef905488f01980a3160d38 GIT binary patch literal 1233 zcmbtS%TE(Q81IoTG#=pKGk#e#-A&x>ZY?dP2QZ3&Q4i8Yf=hI|JEfCuXV%>*f=3^L z8gCxG8T9~vhk%ODzsPTQ+W^e6`t|SI07$j8d!Bz!jZ<`P75P2JrR_ z2}zUs<{Fcf3zJg`g2OHR7HI&*GFX#Sc4f*gL(#G(k_OFCbfAeXpwNxNf-hX+Ma8mwUxhO>*d zSpqE}(rtlV(Lue@?KA`|wnEkkR9Kpgo5Ibm%RDnFZ)`{!6Fcl+7AyU{S`6JXtg2xb z(`*q))?tr{jAyY38K-gC!b`#o>0mf;g@^x-S`2Y`0=SSs*I6WiaY!-PRZ~$k)&z}k z5448paxZ{<%DPWSSF)gq@b{EJxUH$FK@QO4cdUtjS|mfpR}G&=Q2@u@9m0+=4G_ECFr-`>z963ABS#%)Q~417cmU3PoT@0} zGo=z-L)|?JIF@+SWgX(fV*Sp-?KzMFge!5OQVQmIMe}Hr_zXeiF&E2>7;X9toARnD)gOO;A^OjcT7o-tuhG@ zF1mRY?D7g!KpVdRCX}s`zM`iF%<{y5RO&2Pw)25 zp4lC`yYmLs+sh8m@4uU0*cz#i4X*Fg>u|j{y1nf1M3Wez4lQ@(ToUn?L{n literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/md4.el b/xemacs-packages/lisp/ecrypto/md4.el new file mode 100644 index 00000000..f2c1dd91 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/md4.el @@ -0,0 +1,230 @@ +;;; md4.el --- MD4 Message Digest Algorithm. + +;; Copyright (C) 2004 Free Software Foundation, Inc. +;; Copyright (C) 2001 Taro Kawagishi +;; Author: Taro Kawagishi +;; Keywords: MD4 +;; Version: 1.00 +;; Created: February 2001 + +;; This file is part of FLIM (Faithful Library about Internet Message). + +;; This program 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 program 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 this program; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Code: + +;;; +;;; MD4 hash calculation + +(defvar md4-buffer (make-vector 4 '(0 . 0)) + "work buffer of four 32-bit integers") + +;;;###autoload +(defun md4 (in n) + "Returns the MD4 hash string of 16 bytes long for a string IN of N +bytes long. N is required to handle strings containing character 0." + (let (m + (b (cons 0 (* n 8))) + (i 0) + (buf (make-string 128 0)) c4) + ;; initial values + (aset md4-buffer 0 '(26437 . 8961)) ;0x67452301 + (aset md4-buffer 1 '(61389 . 43913)) ;0xefcdab89 + (aset md4-buffer 2 '(39098 . 56574)) ;0x98badcfe + (aset md4-buffer 3 '(4146 . 21622)) ;0x10325476 + + ;; process the string in 64 bits chunks + (while (> n 64) + (setq m (md4-copy64 (substring in 0 64))) + (md4-64 m) + (setq in (substring in 64)) + (setq n (- n 64))) + + ;; process the rest of the string (length is now n <= 64) + (setq i 0) + (while (< i n) + (aset buf i (aref in i)) + (setq i (1+ i))) + (aset buf n 128) ;0x80 + (if (<= n 55) + (progn + (setq c4 (md4-pack-int32 b)) + (aset buf 56 (aref c4 0)) + (aset buf 57 (aref c4 1)) + (aset buf 58 (aref c4 2)) + (aset buf 59 (aref c4 3)) + (setq m (md4-copy64 buf)) + (md4-64 m)) + ;; else + (setq c4 (md4-pack-int32 b)) + (aset buf 120 (aref c4 0)) + (aset buf 121 (aref c4 1)) + (aset buf 122 (aref c4 2)) + (aset buf 123 (aref c4 3)) + (setq m (md4-copy64 buf)) + (md4-64 m) + (setq m (md4-copy64 (substring buf 64))) + (md4-64 m))) + + (concat (md4-pack-int32 (aref md4-buffer 0)) + (md4-pack-int32 (aref md4-buffer 1)) + (md4-pack-int32 (aref md4-buffer 2)) + (md4-pack-int32 (aref md4-buffer 3)))) + +(defsubst md4-F (x y z) (logior (logand x y) (logand (lognot x) z))) +(defsubst md4-G (x y z) (logior (logand x y) (logand x z) (logand y z))) +(defsubst md4-H (x y z) (logxor x y z)) + +(defmacro md4-make-step (name func) + (` + (defun (, name) (a b c d xk s ac) + (let* + ((h1 (+ (car a) ((, func) (car b) (car c) (car d)) (car xk) (car ac))) + (l1 (+ (cdr a) ((, func) (cdr b) (cdr c) (cdr d)) (cdr xk) (cdr ac))) + (h2 (logand 65535 (+ h1 (lsh l1 -16)))) + (l2 (logand 65535 l1)) + ;; cyclic shift of 32 bits integer + (h3 (logand 65535 (if (> s 15) + (+ (lsh h2 (- s 32)) (lsh l2 (- s 16))) + (+ (lsh h2 s) (lsh l2 (- s 16)))))) + (l3 (logand 65535 (if (> s 15) + (+ (lsh l2 (- s 32)) (lsh h2 (- s 16))) + (+ (lsh l2 s) (lsh h2 (- s 16))))))) + (cons h3 l3))))) + +(md4-make-step md4-round1 md4-F) +(md4-make-step md4-round2 md4-G) +(md4-make-step md4-round3 md4-H) + +(defsubst md4-add (x y) + "Return 32-bit sum of 32-bit integers X and Y." + (let ((h (+ (car x) (car y))) + (l (+ (cdr x) (cdr y)))) + (cons (logand 65535 (+ h (lsh l -16))) (logand 65535 l)))) + +(defsubst md4-and (x y) + (cons (logand (car x) (car y)) (logand (cdr x) (cdr y)))) + +(defun md4-64 (m) + "Calculate md4 of 64 bytes chunk M which is represented as 16 pairs of +32 bits integers. The resulting md4 value is placed in md4-buffer." + (let ((a (aref md4-buffer 0)) + (b (aref md4-buffer 1)) + (c (aref md4-buffer 2)) + (d (aref md4-buffer 3))) + (setq a (md4-round1 a b c d (aref m 0) 3 '(0 . 0)) + d (md4-round1 d a b c (aref m 1) 7 '(0 . 0)) + c (md4-round1 c d a b (aref m 2) 11 '(0 . 0)) + b (md4-round1 b c d a (aref m 3) 19 '(0 . 0)) + a (md4-round1 a b c d (aref m 4) 3 '(0 . 0)) + d (md4-round1 d a b c (aref m 5) 7 '(0 . 0)) + c (md4-round1 c d a b (aref m 6) 11 '(0 . 0)) + b (md4-round1 b c d a (aref m 7) 19 '(0 . 0)) + a (md4-round1 a b c d (aref m 8) 3 '(0 . 0)) + d (md4-round1 d a b c (aref m 9) 7 '(0 . 0)) + c (md4-round1 c d a b (aref m 10) 11 '(0 . 0)) + b (md4-round1 b c d a (aref m 11) 19 '(0 . 0)) + a (md4-round1 a b c d (aref m 12) 3 '(0 . 0)) + d (md4-round1 d a b c (aref m 13) 7 '(0 . 0)) + c (md4-round1 c d a b (aref m 14) 11 '(0 . 0)) + b (md4-round1 b c d a (aref m 15) 19 '(0 . 0)) + + a (md4-round2 a b c d (aref m 0) 3 '(23170 . 31129)) ;0x5A827999 + d (md4-round2 d a b c (aref m 4) 5 '(23170 . 31129)) + c (md4-round2 c d a b (aref m 8) 9 '(23170 . 31129)) + b (md4-round2 b c d a (aref m 12) 13 '(23170 . 31129)) + a (md4-round2 a b c d (aref m 1) 3 '(23170 . 31129)) + d (md4-round2 d a b c (aref m 5) 5 '(23170 . 31129)) + c (md4-round2 c d a b (aref m 9) 9 '(23170 . 31129)) + b (md4-round2 b c d a (aref m 13) 13 '(23170 . 31129)) + a (md4-round2 a b c d (aref m 2) 3 '(23170 . 31129)) + d (md4-round2 d a b c (aref m 6) 5 '(23170 . 31129)) + c (md4-round2 c d a b (aref m 10) 9 '(23170 . 31129)) + b (md4-round2 b c d a (aref m 14) 13 '(23170 . 31129)) + a (md4-round2 a b c d (aref m 3) 3 '(23170 . 31129)) + d (md4-round2 d a b c (aref m 7) 5 '(23170 . 31129)) + c (md4-round2 c d a b (aref m 11) 9 '(23170 . 31129)) + b (md4-round2 b c d a (aref m 15) 13 '(23170 . 31129)) + + a (md4-round3 a b c d (aref m 0) 3 '(28377 . 60321)) ;0x6ED9EBA1 + d (md4-round3 d a b c (aref m 8) 9 '(28377 . 60321)) + c (md4-round3 c d a b (aref m 4) 11 '(28377 . 60321)) + b (md4-round3 b c d a (aref m 12) 15 '(28377 . 60321)) + a (md4-round3 a b c d (aref m 2) 3 '(28377 . 60321)) + d (md4-round3 d a b c (aref m 10) 9 '(28377 . 60321)) + c (md4-round3 c d a b (aref m 6) 11 '(28377 . 60321)) + b (md4-round3 b c d a (aref m 14) 15 '(28377 . 60321)) + a (md4-round3 a b c d (aref m 1) 3 '(28377 . 60321)) + d (md4-round3 d a b c (aref m 9) 9 '(28377 . 60321)) + c (md4-round3 c d a b (aref m 5) 11 '(28377 . 60321)) + b (md4-round3 b c d a (aref m 13) 15 '(28377 . 60321)) + a (md4-round3 a b c d (aref m 3) 3 '(28377 . 60321)) + d (md4-round3 d a b c (aref m 11) 9 '(28377 . 60321)) + c (md4-round3 c d a b (aref m 7) 11 '(28377 . 60321)) + b (md4-round3 b c d a (aref m 15) 15 '(28377 . 60321))) + + (aset md4-buffer 0 (md4-add a (aref md4-buffer 0))) + (aset md4-buffer 1 (md4-add b (aref md4-buffer 1))) + (aset md4-buffer 2 (md4-add c (aref md4-buffer 2))) + (aset md4-buffer 3 (md4-add d (aref md4-buffer 3))) + )) + +(defun md4-copy64 (seq) + "Unpack a 64 bytes string into 16 pairs of 32 bits integers." + (let ((int32s (make-vector 16 0)) (i 0) j) + (while (< i 16) + (setq j (* i 4)) + (aset int32s i (cons (+ (aref seq (+ j 2)) (lsh (aref seq (+ j 3)) 8)) + (+ (aref seq j) (lsh (aref seq (1+ j)) 8)))) + (setq i (1+ i))) + int32s)) + +;;; +;;; sub functions + +(defun md4-pack-int16 (int16) + "Pack 16 bits integer in 2 bytes string as little endian." + (let ((str (make-string 2 0))) + (aset str 0 (logand int16 255)) + (aset str 1 (lsh int16 -8)) + str)) + +(defun md4-pack-int32 (int32) + "Pack 32 bits integer in a 4 bytes string as little endian. A 32 bits +integer is represented as a pair of two 16 bits integers (cons high low)." + (let ((str (make-string 4 0)) + (h (car int32)) (l (cdr int32))) + (aset str 0 (logand l 255)) + (aset str 1 (lsh l -8)) + (aset str 2 (logand h 255)) + (aset str 3 (lsh h -8)) + str)) + +(defun md4-unpack-int16 (str) + (if (eq 2 (length str)) + (+ (lsh (aref str 1) 8) (aref str 0)) + (error "%s is not 2 bytes long" str))) + +(defun md4-unpack-int32 (str) + (if (eq 4 (length str)) + (cons (+ (lsh (aref str 3) 8) (aref str 2)) + (+ (lsh (aref str 1) 8) (aref str 0))) + (error "%s is not 4 bytes long" str))) + +(provide 'md4) + +;;; arch-tag: 99d706fe-089b-42ea-9507-67ae41091e6e +;;; md4.el ends here diff --git a/xemacs-packages/lisp/ecrypto/md4.elc b/xemacs-packages/lisp/ecrypto/md4.elc new file mode 100644 index 0000000000000000000000000000000000000000..94cdf7ef819ae4ca0c1009b3b64797915b8130e5 GIT binary patch literal 7135 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 +;; Keywords: MD5, RFC 1321 + +;; This file is part of FLIM (Faithful Library about Internet Message). + +;; This program 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 program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;;; Code: + +(provide 'md5-dl) ; beware of circular dependency. +(eval-when-compile (require 'md5)) ; md5-dl-module. + +;;; This file is loaded (from "md5.el") only when md5-dl-module is exists. +(defvar md5-dl-handle (dynamic-link md5-dl-module)) + +;;; md5-dl-module provides `md5-string'. +(dynamic-call "emacs_md5_init" md5-dl-handle) + +(defun md5-region (beg end) + (md5-string (buffer-substring-no-properties beg end))) + +;;; Note that v21 `md5' takes two more args: CODING and NOERROR. +(defun md5 (object &optional beg end) + "Return the MD5 (a secure message digest algorithm) of an object. +OBJECT is either a string or a buffer. +Optional arguments BEG and END denote buffer positions for computing the +hash of a portion of OBJECT." + (if (stringp object) + (md5-string object) + (save-excursion + (set-buffer object) + (md5-region (or beg (point-min)) (or end (point-max)))))) + +(provide 'md5-dl) + +;;; md5-dl.el ends here diff --git a/xemacs-packages/lisp/ecrypto/md5-dl.elc b/xemacs-packages/lisp/ecrypto/md5-dl.elc new file mode 100644 index 0000000000000000000000000000000000000000..591b1bcfe67284b0310f8ebae71eace8e829d372 GIT binary patch literal 1234 zcmZWo+iuh_5bYz)BjTOe6w%}%*$b4G?h7ickPsIMctBz+aN^0vtYZh;>4i5Wq*nY2 zh;OJU*S}(%q?F4_tKG5BoH=u5Je}RYeQ9N7C74d9kn5@z5;w~ctGDLSi|H7jJCGNo7>|XFd2YPdXhsF-oa#$}HN!AF- zhYqb99$>|Co75~{vIW{9=H{?=dRXy|gv%6VOWA^8k0=CHo{ZD$5Y^1(C5$&?2=6sj zrr}9xL{*3IZ00H9ev=EHw&~fSL*LdpLps^)aZ@jRl#FgB<4K3swG)+i!s)jC-7f{{;2M;6fCs`l5DGdC%83FKEnY19aE0~MAjLh7Kub_Yxs*6!pSI%<2Yz>XbhDIU;egr9rl?$pLIdE zo#Zx)M0-VNdh^B@R4$R4@kCOGF;zzQ8veTgB_!3PeD8VU9fI)m%i#EAu68bdJsEsF z`gZbtbubT)fBd{K50654-f2oovWRx3k1EX@ivBN98@(rpwZj3&f;G}5y;M?_^hdxC z6{|!}g4ObOK)Wa*Y@K>R6fcAlF5HFdaS-`DDae&|&uwtw=fCzm%5VXwIPKZz(^b+u z@S^De{Dp^hLx8L)3N(prvVJN`C#1GU;{;l&u^R_#w9IpTG*N0B_a;9hj++3T3PJTP-`nZoOYZ@{Bvm>?Uq*=l+2c`1VT|a4dBPDYXL5J)EoQhj*uQH8^@dSFex1tbTfn7e2k^^DzF?*Ph`Id(Vfm Z3)di8y8 + +;; LCD Archive Entry: +;; md5|Gareth Rees|gdr11@cl.cam.ac.uk| +;; MD5 cryptographic message digest algorithm| +;; 13-Nov-95|1.0|~/misc/md5.el.Z| + +;;; Details: ------------------------------------------------------------------ + +;; This is a direct translation into Emacs LISP of the reference C +;; implementation of the MD5 Message-Digest Algorithm written by RSA +;; Data Security, Inc. +;; +;; The algorithm takes a message (that is, a string of bytes) and +;; computes a 16-byte checksum or "digest" for the message. This digest +;; is supposed to be cryptographically strong in the sense that if you +;; are given a 16-byte digest D, then there is no easier way to +;; construct a message whose digest is D than to exhaustively search the +;; space of messages. However, the robustness of the algorithm has not +;; been proven, and a similar algorithm (MD4) was shown to be unsound, +;; so treat with caution! +;; +;; The C algorithm uses 32-bit integers; because GNU Emacs +;; implementations provide 28-bit integers (with 24-bit integers on +;; versions prior to 19.29), the code represents a 32-bit integer as the +;; cons of two 16-bit integers. The most significant word is stored in +;; the car and the least significant in the cdr. The algorithm requires +;; at least 17 bits of integer representation in order to represent the +;; carry from a 16-bit addition. + +;;; Usage: -------------------------------------------------------------------- + +;; To compute the MD5 Message Digest for a message M (represented as a +;; string or as a vector of bytes), call +;; +;; (md5-encode M) +;; +;; which returns the message digest as a vector of 16 bytes. If you +;; need to supply the message in pieces M1, M2, ... Mn, then call +;; +;; (md5-init) +;; (md5-update M1) +;; (md5-update M2) +;; ... +;; (md5-update Mn) +;; (md5-final) + +;;; Copyright and licence: ---------------------------------------------------- + +;; Copyright (C) 1995, 1996, 1997 by Gareth Rees +;; Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm +;; +;; md5.el 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. +;; +;; md5.el 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. +;; +;; The original copyright notice is given below, as required by the +;; licence for the original code. This code is distributed under *both* +;; RSA's original licence and the GNU General Public Licence. (There +;; should be no problems, as the former is more liberal than the +;; latter). + +;;; Original copyright notice: ------------------------------------------------ + +;; Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. +;; +;; License to copy and use this software is granted provided that it is +;; identified as the "RSA Data Security, Inc. MD5 Message- Digest +;; Algorithm" in all material mentioning or referencing this software or +;; this function. +;; +;; License is also granted to make and use derivative works provided +;; that such works are identified as "derived from the RSA Data +;; Security, Inc. MD5 Message-Digest Algorithm" in all material +;; mentioning or referencing the derived work. +;; +;; RSA Data Security, Inc. makes no representations concerning either +;; the merchantability of this software or the suitability of this +;; software for any particular purpose. It is provided "as is" without +;; express or implied warranty of any kind. +;; +;; These notices must be retained in any copies of any part of this +;; documentation and/or software. + +;;; Code: --------------------------------------------------------------------- + +(defcustom md5-program "md5" + "*Program that reads a message on its standard input and writes an +MD5 digest on its output." + :type 'string) + +(defcustom md5-maximum-internal-length 4096 + "*The maximum size of a piece of data that should use the MD5 routines +written in lisp. If a message exceeds this, it will be run through an +external filter for processing. Also see the `md5-program' variable. +This variable has no effect if you call the md5-init|update|final +functions - only used by the `md5' function's simpler interface." + :type 'integer) + +(defvar md5-bits (make-vector 4 0) + "Number of bits handled, modulo 2^64. +Represented as four 16-bit numbers, least significant first.") +(defvar md5-buffer (make-vector 4 '(0 . 0)) + "Scratch buffer (four 32-bit integers).") +(defvar md5-input (make-vector 64 0) + "Input buffer (64 bytes).") + +(defun md5-unhex (x) + (if (> x ?9) + (if (>= x ?a) + (+ 10 (- x ?a)) + (+ 10 (- x ?A))) + (- x ?0))) + +(defun md5-encode (message) + "Encodes MESSAGE using the MD5 message digest algorithm. +MESSAGE must be a string or an array of bytes. +Returns a vector of 16 bytes containing the message digest." + (if (or (null md5-maximum-internal-length) + (<= (length message) md5-maximum-internal-length)) + (progn + (md5-init) + (md5-update message) + (md5-final)) + (save-excursion + (set-buffer (get-buffer-create " *md5-work*")) + (erase-buffer) + (insert message) + (call-process-region (point-min) (point-max) + md5-program + t (current-buffer)) + ;; MD5 digest is 32 chars long + ;; mddriver adds a newline to make neaten output for tty + ;; viewing, make sure we leave it behind. + (let ((data (buffer-substring (point-min) (+ (point-min) 32))) + (vec (make-vector 16 0)) + (ctr 0)) + (while (< ctr 16) + (aset vec ctr (+ (* 16 (md5-unhex (aref data (* ctr 2)))) + (md5-unhex (aref data (1+ (* ctr 2)))))) + (setq ctr (1+ ctr))))))) + +(defsubst md5-add (x y) + "Return 32-bit sum of 32-bit integers X and Y." + (let ((m (+ (car x) (car y))) + (l (+ (cdr x) (cdr y)))) + (cons (logand 65535 (+ m (lsh l -16))) (logand l 65535)))) + +;; FF, GG, HH and II are basic MD5 functions, providing transformations +;; for rounds 1, 2, 3 and 4 respectively. Each function follows this +;; pattern of computation (where ROTATE(x,y) means rotate 32-bit value x +;; by y bits to the left): +;; +;; FF(a,b,c,d,x,s,ac) = ROTATE(a + F(b,c,d) + x + ac,s) + b +;; +;; so we use the macro `md5-make-step' to construct each one. The +;; helper functions F, G, H and I operate on 16-bit numbers; the full +;; operation splits its inputs, operates on the halves separately and +;; then puts the results together. + +(defsubst md5-F (x y z) (logior (logand x y) (logand (lognot x) z))) +(defsubst md5-G (x y z) (logior (logand x z) (logand y (lognot z)))) +(defsubst md5-H (x y z) (logxor x y z)) +(defsubst md5-I (x y z) (logxor y (logior x (logand 65535 (lognot z))))) + +(defmacro md5-make-step (name func) + (` + (defun (, name) (a b c d x s ac) + (let* + ((m1 (+ (car a) ((, func) (car b) (car c) (car d)) (car x) (car ac))) + (l1 (+ (cdr a) ((, func) (cdr b) (cdr c) (cdr d)) (cdr x) (cdr ac))) + (m2 (logand 65535 (+ m1 (lsh l1 -16)))) + (l2 (logand 65535 l1)) + (m3 (logand 65535 (if (> s 15) + (+ (lsh m2 (- s 32)) (lsh l2 (- s 16))) + (+ (lsh m2 s) (lsh l2 (- s 16)))))) + (l3 (logand 65535 (if (> s 15) + (+ (lsh l2 (- s 32)) (lsh m2 (- s 16))) + (+ (lsh l2 s) (lsh m2 (- s 16))))))) + (md5-add (cons m3 l3) b))))) + +(md5-make-step md5-FF md5-F) +(md5-make-step md5-GG md5-G) +(md5-make-step md5-HH md5-H) +(md5-make-step md5-II md5-I) + +(defun md5-init () + "Initialise the state of the message-digest routines." + (aset md5-bits 0 0) + (aset md5-bits 1 0) + (aset md5-bits 2 0) + (aset md5-bits 3 0) + (aset md5-buffer 0 '(26437 . 8961)) + (aset md5-buffer 1 '(61389 . 43913)) + (aset md5-buffer 2 '(39098 . 56574)) + (aset md5-buffer 3 '( 4146 . 21622))) + +(defun md5-update (string) + "Update the current MD5 state with STRING (an array of bytes)." + (let ((len (length string)) + (i 0) + (j 0)) + (while (< i len) + ;; Compute number of bytes modulo 64 + (setq j (% (/ (aref md5-bits 0) 8) 64)) + + ;; Store this byte (truncating to 8 bits to be sure) + (aset md5-input j (logand 255 (aref string i))) + + ;; Update number of bits by 8 (modulo 2^64) + (let ((c 8) (k 0)) + (while (and (> c 0) (< k 4)) + (let ((b (aref md5-bits k))) + (aset md5-bits k (logand 65535 (+ b c))) + (setq c (if (> b (- 65535 c)) 1 0) + k (1+ k))))) + + ;; Increment number of bytes processed + (setq i (1+ i)) + + ;; When 64 bytes accumulated, pack them into sixteen 32-bit + ;; integers in the array `in' and then transform them. + (if (= j 63) + (let ((in (make-vector 16 (cons 0 0))) + (k 0) + (kk 0)) + (while (< k 16) + (aset in k (md5-pack md5-input kk)) + (setq k (+ k 1) kk (+ kk 4))) + (md5-transform in)))))) + +(defun md5-pack (array i) + "Pack the four bytes at ARRAY reference I to I+3 into a 32-bit integer." + (cons (+ (lsh (aref array (+ i 3)) 8) (aref array (+ i 2))) + (+ (lsh (aref array (+ i 1)) 8) (aref array (+ i 0))))) + +(defun md5-byte (array n b) + "Unpack byte B (0 to 3) from Nth member of ARRAY of 32-bit integers." + (let ((e (aref array n))) + (cond ((eq b 0) (logand 255 (cdr e))) + ((eq b 1) (lsh (cdr e) -8)) + ((eq b 2) (logand 255 (car e))) + ((eq b 3) (lsh (car e) -8))))) + +(defun md5-final () + (let ((in (make-vector 16 (cons 0 0))) + (j 0) + (digest (make-vector 16 0)) + (padding)) + + ;; Save the number of bits in the message + (aset in 14 (cons (aref md5-bits 1) (aref md5-bits 0))) + (aset in 15 (cons (aref md5-bits 3) (aref md5-bits 2))) + + ;; Compute number of bytes modulo 64 + (setq j (% (/ (aref md5-bits 0) 8) 64)) + + ;; Pad out computation to 56 bytes modulo 64 + (setq padding (make-vector (if (< j 56) (- 56 j) (- 120 j)) 0)) + (aset padding 0 128) + (md5-update padding) + + ;; Append length in bits and transform + (let ((k 0) (kk 0)) + (while (< k 14) + (aset in k (md5-pack md5-input kk)) + (setq k (+ k 1) kk (+ kk 4)))) + (md5-transform in) + + ;; Store the results in the digest + (let ((k 0) (kk 0)) + (while (< k 4) + (aset digest (+ kk 0) (md5-byte md5-buffer k 0)) + (aset digest (+ kk 1) (md5-byte md5-buffer k 1)) + (aset digest (+ kk 2) (md5-byte md5-buffer k 2)) + (aset digest (+ kk 3) (md5-byte md5-buffer k 3)) + (setq k (+ k 1) kk (+ kk 4)))) + + ;; Return digest + digest)) + +;; It says in the RSA source, "Note that if the Mysterious Constants are +;; arranged backwards in little-endian order and decrypted with the DES +;; they produce OCCULT MESSAGES!" Security through obscurity? + +(defun md5-transform (in) + "Basic MD5 step. Transform md5-buffer based on array IN." + (let ((a (aref md5-buffer 0)) + (b (aref md5-buffer 1)) + (c (aref md5-buffer 2)) + (d (aref md5-buffer 3))) + (setq + a (md5-FF a b c d (aref in 0) 7 '(55146 . 42104)) + d (md5-FF d a b c (aref in 1) 12 '(59591 . 46934)) + c (md5-FF c d a b (aref in 2) 17 '( 9248 . 28891)) + b (md5-FF b c d a (aref in 3) 22 '(49597 . 52974)) + a (md5-FF a b c d (aref in 4) 7 '(62844 . 4015)) + d (md5-FF d a b c (aref in 5) 12 '(18311 . 50730)) + c (md5-FF c d a b (aref in 6) 17 '(43056 . 17939)) + b (md5-FF b c d a (aref in 7) 22 '(64838 . 38145)) + a (md5-FF a b c d (aref in 8) 7 '(27008 . 39128)) + d (md5-FF d a b c (aref in 9) 12 '(35652 . 63407)) + c (md5-FF c d a b (aref in 10) 17 '(65535 . 23473)) + b (md5-FF b c d a (aref in 11) 22 '(35164 . 55230)) + a (md5-FF a b c d (aref in 12) 7 '(27536 . 4386)) + d (md5-FF d a b c (aref in 13) 12 '(64920 . 29075)) + c (md5-FF c d a b (aref in 14) 17 '(42617 . 17294)) + b (md5-FF b c d a (aref in 15) 22 '(18868 . 2081)) + a (md5-GG a b c d (aref in 1) 5 '(63006 . 9570)) + d (md5-GG d a b c (aref in 6) 9 '(49216 . 45888)) + c (md5-GG c d a b (aref in 11) 14 '( 9822 . 23121)) + b (md5-GG b c d a (aref in 0) 20 '(59830 . 51114)) + a (md5-GG a b c d (aref in 5) 5 '(54831 . 4189)) + d (md5-GG d a b c (aref in 10) 9 '( 580 . 5203)) + c (md5-GG c d a b (aref in 15) 14 '(55457 . 59009)) + b (md5-GG b c d a (aref in 4) 20 '(59347 . 64456)) + a (md5-GG a b c d (aref in 9) 5 '( 8673 . 52710)) + d (md5-GG d a b c (aref in 14) 9 '(49975 . 2006)) + c (md5-GG c d a b (aref in 3) 14 '(62677 . 3463)) + b (md5-GG b c d a (aref in 8) 20 '(17754 . 5357)) + a (md5-GG a b c d (aref in 13) 5 '(43491 . 59653)) + d (md5-GG d a b c (aref in 2) 9 '(64751 . 41976)) + c (md5-GG c d a b (aref in 7) 14 '(26479 . 729)) + b (md5-GG b c d a (aref in 12) 20 '(36138 . 19594)) + a (md5-HH a b c d (aref in 5) 4 '(65530 . 14658)) + d (md5-HH d a b c (aref in 8) 11 '(34673 . 63105)) + c (md5-HH c d a b (aref in 11) 16 '(28061 . 24866)) + b (md5-HH b c d a (aref in 14) 23 '(64997 . 14348)) + a (md5-HH a b c d (aref in 1) 4 '(42174 . 59972)) + d (md5-HH d a b c (aref in 4) 11 '(19422 . 53161)) + c (md5-HH c d a b (aref in 7) 16 '(63163 . 19296)) + b (md5-HH b c d a (aref in 10) 23 '(48831 . 48240)) + a (md5-HH a b c d (aref in 13) 4 '(10395 . 32454)) + d (md5-HH d a b c (aref in 0) 11 '(60065 . 10234)) + c (md5-HH c d a b (aref in 3) 16 '(54511 . 12421)) + b (md5-HH b c d a (aref in 6) 23 '( 1160 . 7429)) + a (md5-HH a b c d (aref in 9) 4 '(55764 . 53305)) + d (md5-HH d a b c (aref in 12) 11 '(59099 . 39397)) + c (md5-HH c d a b (aref in 15) 16 '( 8098 . 31992)) + b (md5-HH b c d a (aref in 2) 23 '(50348 . 22117)) + a (md5-II a b c d (aref in 0) 6 '(62505 . 8772)) + d (md5-II d a b c (aref in 7) 10 '(17194 . 65431)) + c (md5-II c d a b (aref in 14) 15 '(43924 . 9127)) + b (md5-II b c d a (aref in 5) 21 '(64659 . 41017)) + a (md5-II a b c d (aref in 12) 6 '(25947 . 22979)) + d (md5-II d a b c (aref in 3) 10 '(36620 . 52370)) + c (md5-II c d a b (aref in 10) 15 '(65519 . 62589)) + b (md5-II b c d a (aref in 1) 21 '(34180 . 24017)) + a (md5-II a b c d (aref in 8) 6 '(28584 . 32335)) + d (md5-II d a b c (aref in 15) 10 '(65068 . 59104)) + c (md5-II c d a b (aref in 6) 15 '(41729 . 17172)) + b (md5-II b c d a (aref in 13) 21 '(19976 . 4513)) + a (md5-II a b c d (aref in 4) 6 '(63315 . 32386)) + d (md5-II d a b c (aref in 11) 10 '(48442 . 62005)) + c (md5-II c d a b (aref in 2) 15 '(10967 . 53947)) + b (md5-II b c d a (aref in 9) 21 '(60294 . 54161))) + + (aset md5-buffer 0 (md5-add (aref md5-buffer 0) a)) + (aset md5-buffer 1 (md5-add (aref md5-buffer 1) b)) + (aset md5-buffer 2 (md5-add (aref md5-buffer 2) c)) + (aset md5-buffer 3 (md5-add (aref md5-buffer 3) d)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Here begins the merger with the XEmacs API and the md5.el from the URL +;;; package. Courtesy wmperry@cs.indiana.edu +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;###autoload +(defun md5 (object &optional start end) + "Return the MD5 (a secure message digest algorithm) of an object. +OBJECT is either a string or a buffer. +Optional arguments START and END denote buffer positions for computing the +hash of a portion of OBJECT." + (let ((buffer nil)) + (unwind-protect + (save-excursion + (setq buffer (generate-new-buffer " *md5-work*")) + (set-buffer buffer) + (cond + ((bufferp object) + (insert-buffer-substring object start end)) + ((stringp object) + (insert (if (or start end) + (substring object start end) + object))) + (t nil)) + (prog1 + (if (or (null md5-maximum-internal-length) + (<= (point-max) md5-maximum-internal-length)) + (mapconcat + (function (lambda (node) (format "%02x" node))) + (md5-encode (buffer-string)) + "") + (call-process-region (point-min) (point-max) + shell-file-name + t buffer nil + shell-command-switch md5-program) + ;; MD5 digest is 32 chars long + ;; mddriver adds a newline to make neaten output for tty + ;; viewing, make sure we leave it behind. + (buffer-substring (point-min) (+ (point-min) 32))) + (kill-buffer buffer))) + (and buffer (buffer-name buffer) (kill-buffer buffer) nil)))) + +(provide 'md5-el) diff --git a/xemacs-packages/lisp/ecrypto/md5-el.elc b/xemacs-packages/lisp/ecrypto/md5-el.elc new file mode 100644 index 0000000000000000000000000000000000000000..1201587bfe6efd0e7096082c62437aa5224cf54b GIT binary patch literal 10233 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/md5.el b/xemacs-packages/lisp/ecrypto/md5.el new file mode 100644 index 00000000..8c4d7c05 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/md5.el @@ -0,0 +1,79 @@ +;;; md5.el --- MD5 Message Digest Algorithm. + +;; Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +;; Author: Shuhei KOBAYASHI +;; Keywords: MD5, RFC 1321 + +;; This file is part of FLIM (Faithful Library about Internet Message). + +;; This program 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 program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Test cases from RFC 1321. +;; +;; (md5 "") +;; => d41d8cd98f00b204e9800998ecf8427e +;; +;; (md5 "a") +;; => 0cc175b9c0f1b6a831c399e269772661 +;; +;; (md5 "abc") +;; => 900150983cd24fb0d6963f7d28e17f72 +;; +;; (md5 "message digest") +;; => f96b697d7cb7938d525a2f31aaf161d0 +;; +;; (md5 "abcdefghijklmnopqrstuvwxyz") +;; => c3fcd3d76192e4007dfb496cca67e13b +;; +;; (md5 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") +;; => d174ab98d277d9f5a5611c2c9f419d9f +;; +;; (md5 "12345678901234567890123456789012345678901234567890123456789012345678901234567890") +;; => 57edf4a22be3c955ac49da2e2107b67a + +;;; Code: + +(defvar md5-dl-module + (cond + ((and (fboundp 'md5) + (subrp (symbol-function 'md5))) + nil) + ((fboundp 'dynamic-link) + ;; Should we take care of `dynamic-link-path'? + (let ((path (expand-file-name "md5.so" exec-directory))) + (if (file-exists-p path) + path + nil))) + (t + nil))) + +(cond + ((and (fboundp 'md5) + (subrp (symbol-function 'md5))) + ;; do nothing. + ) + ((and (stringp md5-dl-module) + (file-exists-p md5-dl-module)) + (require 'md5-dl)) + (t + (require 'md5-el))) + +(provide 'md5) + +;;; md5.el ends here diff --git a/xemacs-packages/lisp/ecrypto/md5.elc b/xemacs-packages/lisp/ecrypto/md5.elc new file mode 100644 index 0000000000000000000000000000000000000000..4a045ea32e7847a6117d25639be987412660247d GIT binary patch literal 867 zcmZWnO>Yx15bcqsH^hz0>|UBZcsGe?OOpc#)C-hTFGv&#$M!Z>ytZq5(}WvR1(D!_ z_yt^P^CK!j%SQ|RBxX0Ms?wEKyB@!J^WMz#wzePNSz20Z^m;vDrm#{84*dz};X~?Z zE>t>_L1>d|5x{78hVPEB&{>Dp{cd}s+g^uGtF=}WPZAF{D1DD%WpHl%yPXM(wj4JIr2S}Ih{S0iAA`4Y=^+UY%LS{m2@+8YVP zPs*ZiU}xZDVPkl{Rq?@g$s|wf^!_A>%F`7?+Syp(dX?%HX>F2rXO1>D$U?rRp{gZ4 znw`hP01ve(bb?{a49D-mK%x$AK$`$!EPVi}VXmRQnKl|tnM0Fm4$ZzPHMg)jH@vWu zG?t-h-2V`3*r40J#DKVd#+>SD`rxGABT9I0;TkQ(omQMANu$OI=deWlYTnaTIH3M& z$~j)m_0}nY+Dry$YlrI4& (length ans) 0) + (setq newans (substring ans 0 -1)) + (fillarray ans 0) + (setq ans newans)))) + (if quit-flag + ;; Emulate a true quit, except that we have to return a value. + (prog1 + (setq quit-flag nil) + (message "Quit") + (beep t)) + (message "") + ans))) + +(provide 'paranoid) diff --git a/xemacs-packages/lisp/ecrypto/paranoid.elc b/xemacs-packages/lisp/ecrypto/paranoid.elc new file mode 100644 index 0000000000000000000000000000000000000000..c77fee69c025a58200daff50c9b6884dcfd59d3a GIT binary patch literal 1626 zcmZWp+fE!u5aliMWU=G~ONpI0#gK>@iJ8457z__M!h|@&hJZJU#1gr8rgx{cGu`9v z9+u5J3L7QLOTGg54sN+$onOdbq`C(OY_GJv+f~)obxxh?`K6V`v5}DxXMTPjB9Y}R zr7^SzzmgO#dzGRZZN)cfKd%Qi+)BwB45H@DcpQwv|chFxJZO>uZrlw~VM}?G>>mU^*4pPME zS&Fwh&cxm6*#@jr5(5E+RiY$P#wmynXu6}pD#a)R`b;OHK=z_UVBi!Owj|Ys=qf;0&DB557r)GFqAA{+`HV_wsu1S?kw9|O%g%l+L$`A^Y=!8l~Cxrix z*GFwV6q@2OqH&?nqXVQu^iY*X?vfeWt;Z4`;bEl_B^HkKMgrAEW5?4p%Y`J8r31g@ zt+lz$Xdk<+6wc)q^06T@3ON-ycCo{-b_=&Jq#P)8h0ZFEOeGX>-c!V9XTGAN!8@JxPb>pp@Z@2j2zh^&Oz1ed2euUxJPtAjGejYu+-Rbb! z@U{K8@=NpZ>&maq!`;en&4b-jw5?TsZypTGsH5xqA6EWo9)4f>vw8U4=wFrbwbx6} ztJn9v(dCoR4qEQ$$=|CN*0C!G-yRRIojo1j`{#6gZ-4jfXnb!peB~<_HZ$xq@`=25 zgN*Ee5mV4fNf*)MU~t+e99xIlP~f_@@iowJehl3Al#6}C35*gV1G*EXg<{(j7Fu5{ z8(p0NsbmZn)gHp>FolUfAj$UsmB_fxFGMM>a`j?=7!3>Xj0C +;; Created: 2003-12-21 +;; Keywords: password cache passphrase key + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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. + +;;; Commentary: + +;; Greatly influenced by pgg.el written by Daiki Ueno, with timer +;; fixes for XEmacs by Katsumi Yamaoka. In fact, this is mostly just +;; a rip-off. +;; +;; (password-read "Password? " "test") +;; ;; Minibuffer prompt for password. +;; => "foo" +;; +;; (password-cache-add "test" "foo") +;; => nil + +;; Note the previous two can be replaced with: +;; (password-read-and-add "Password? " "test") +;; ;; Minibuffer prompt for password. +;; => "foo" +;; ;; "foo" is now cached with key "test" + + +;; (password-read "Password? " "test") +;; ;; No minibuffer prompt +;; => "foo" +;; +;; (password-read "Password? " "test") +;; ;; No minibuffer prompt +;; => "foo" +;; +;; ;; Wait `password-cache-expiry' seconds. +;; +;; (password-read "Password? " "test") +;; ;; Minibuffer prompt for password is back. +;; => "foo" + +;;; Code: + +(eval-when-compile + (require 'cl)) + +;; XEmacs has a buggy version of run-at-time. This defines a +;; non-buggy version of the same. +(defalias + 'password-run-at-time + (if (condition-case nil + (progn + (unless (or itimer-process itimer-timer) + (itimer-driver-start)) + ;; Check whether there is a bug to which the difference of + ;; the present time and the time when the itimer driver was + ;; woken up is subtracted from the initial itimer value. + (let* ((inhibit-quit t) + (ctime (current-time)) + (itimer-timer-last-wakeup + (prog1 + ctime + (setcar ctime (1- (car ctime))))) + (itimer-list nil) + (itimer (start-itimer "run-at-time" 'ignore 5))) + (sleep-for 0.1) ;; Accept the timeout interrupt. + (prog1 + (> (itimer-value itimer) 0) + (delete-itimer itimer)))) + (error nil)) + (lambda (time repeat function &rest args) + "Function emulating the function of the same name of Emacs. +TIME should be nil meaning now, or a number of seconds from now. +Return an itimer object which can be used in either `delete-itimer' +or `cancel-timer'." + (apply #'start-itimer "run-at-time" + function (if time (max time 1e-9) 1e-9) + repeat nil t args)) + (lambda (time repeat function &rest args) + "Function emulating the function of the same name of Emacs. +It works correctly for TIME even if there is a bug in the XEmacs core. +TIME should be nil meaning now, or a number of seconds from now. +Return an itimer object which can be used in either `delete-itimer' +or `cancel-timer'." + (let ((itimers (list nil))) + (setcar + itimers + (apply #'start-itimer "fixed-run-at-time" + (lambda (itimers repeat function &rest args) + (let ((itimer (car itimers))) + (if repeat + (progn + (set-itimer-function + itimer + (lambda (itimer repeat function &rest args) + (set-itimer-restart itimer repeat) + (set-itimer-function itimer function) + (set-itimer-function-arguments itimer args) + (apply function args))) + (set-itimer-function-arguments + itimer + (append (list itimer repeat function) args))) + (set-itimer-function + itimer + (lambda (itimer function &rest args) + (delete-itimer itimer) + (apply function args))) + (set-itimer-function-arguments + itimer + (append (list itimer function) args))))) + 1e-9 (if time (max time 1e-9) 1e-9) + nil t itimers repeat function args)))))) + +(defcustom password-cache t + "Whether to cache passwords." + :group 'password + :type 'boolean) + +(defcustom password-cache-expiry 16 + "How many seconds passwords are cached, or nil to disable expiring. +Whether passwords are cached at all is controlled by `password-cache'." + :group 'password + :type '(choice (const :tag "Never" nil) + (integer :tag "Seconds"))) + +(defvar password-data (make-vector 7 0)) + +(defun password-read (prompt &optional key) + "Read password, for use with KEY, from user, or from cache if wanted. +KEY indicate the purpose of the password, so the cache can +separate passwords. The cache is not used if KEY is nil. It is +typically a string. +The variable `password-cache' control whether the cache is used." + (or (and password-cache + key + (symbol-value (intern-soft key password-data))) + (read-passwd prompt))) + +(defun password-read-and-add (prompt &optional key) + "Read password, for use with KEY, from user, or from cache if wanted. +Then store the password in the cache. Uses `password-read' and +`password-cache-add'." + (let ((password (password-read prompt key))) + (when (and password key) + (password-cache-add key password)) + password)) + +(defun password-cache-remove (key) + "Remove password indexed by KEY from password cache. +This is typically run be a timer setup from `password-cache-add', +but can be invoked at any time to forcefully remove passwords +from the cache. This may be useful when it has been detected +that a password is invalid, so that `password-read' query the +user again." + (let ((password (symbol-value (intern-soft key password-data)))) + (when password + (fillarray password ?_) + (unintern key password-data)))) + +(defun password-cache-add (key password) + "Add password to cache. +The password is removed by a timer after `password-cache-expiry' +seconds." + (set (intern key password-data) password) + (when password-cache-expiry + (password-run-at-time password-cache-expiry nil + #'password-cache-remove + key)) + nil) + +(provide 'password) + +;;; arch-tag: ab160494-16c8-4c68-a4a1-73eebf6686e5 +;;; password.el ends here diff --git a/xemacs-packages/lisp/ecrypto/password.elc b/xemacs-packages/lisp/ecrypto/password.elc new file mode 100644 index 0000000000000000000000000000000000000000..5e86cd6f4d2ad0e71e061807734a17c006d55cc2 GIT binary patch literal 4266 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/rc16.el b/xemacs-packages/lisp/ecrypto/rc16.el new file mode 100644 index 00000000..911a4507 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/rc16.el @@ -0,0 +1,122 @@ +;;; rc16.el -- rc16, by proff@iq.org, translated to elisp + +;; Copyright (C) 1998 Ray Jones + +;; Author: Ray Jones, rjones@pobox.com +;; Keywords: RNG, rc4, rc16, stream cipher +;; Created: 1998-04-14 + +;; This program 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 program 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 this program; if not, you can either send email to this +;; program's maintainer or write to: The Free Software Foundation, +;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. + + +;; rc16-context functions +(defun rc16-create-context () + (vector 0 0 (make-vector 65536 0))) + +(defsubst rc16-context-x (context) + (aref context 0)) + +(defsubst rc16-context-y (context) + (aref context 1)) + +(defsubst rc16-context-state (context) + (aref context 2)) + +;; sigh. why doesn't elisp have (setf (aref ...))? +(defsubst rc16-context-set-x (context val) + (aset context 0 val)) + +(defsubst rc16-context-set-y (context val) + (aset context 1 val)) + +;; set a key, init the context +(defun rc16-set-key (context key) + (let ((state (rc16-context-state context))) + ;; init context + (rc16-context-set-x context 0) + (rc16-context-set-y context 0) + (let ((counter 0)) + (while (< counter 65536) + (aset state counter counter) + (setq counter (1+ counter)))) + + ;; mix in key + (let ((keyidx 0) + (keylen (length key)) + (stateidx 0) + (counter 0) + temp1 temp2) + (while (< counter 65536) + (setq temp1 (aref state counter)) + (setq stateidx (logand ?\xffff (+ stateidx temp1 (aref key keyidx)))) + (setq temp2 (aref state stateidx)) + (aset state stateidx temp1) + (aset state counter temp2) + (setq keyidx (1+ keyidx)) + (if (= keyidx keylen) (setq keyidx 0)) + (setq counter (1+ counter)))))) + +;; mixin some randomness, a little at a time +;; added by Ray. is this a good thing? +(defun rc16-mixin (context val) + (let* ((state (rc16-context-state context)) + (x (logand ?\xffff (1+ (rc16-context-x context)))) + (sx (aref state x)) + (y (logand ?\xffff + (logxor val + (+ sx (rc16-context-y context))))) + (sy (aref state y))) + (rc16-context-set-x context x) + (rc16-context-set-y context y) + (aset state y sx) + (aset state x sy) + nil)) + +;; return a random value +(defun rc16-short (context) + (let* ((state (rc16-context-state context)) + (x (logand ?\xffff (1+ (rc16-context-x context)))) + (sx (aref state x)) + (y (logand ?\xffff (+ sx (rc16-context-y context)))) + (sy (aref state y))) + (rc16-context-set-x context x) + (rc16-context-set-y context y) + (aset state y sx) + (aset state x sy) + (aref state (logand ?\xffff (+ sx sy))))) + +(defun rc16-encrypt (context data) + (let* ((cipher (make-string (length data) 0)) + (rc16-val (rc16-short context)) + (hi-byte (ash rc16-val -8)) + (lo-byte (logand rc16-val 255)) + (bytes-left 2) + (count 0) + (length (length data))) + (while (< count length) + (aset cipher count (logxor (aref data count) hi-byte)) + (setq bytes-left (1- bytes-left)) + (if (= bytes-left 0) + (progn + (setq bytes-left 2) + (setq rc16-val (rc16-short context)) + (setq hi-byte (ash rc16-val -8)) + (setq lo-byte (logand rc16-val 255))) + (setq hi-byte lo-byte)) + (setq count (1+ count))) + cipher)) + +(provide 'rc16) diff --git a/xemacs-packages/lisp/ecrypto/rc16.elc b/xemacs-packages/lisp/ecrypto/rc16.elc new file mode 100644 index 0000000000000000000000000000000000000000..1f96b9dd4b1b2d2fd66e3d5d2162f7a785ea52ef GIT binary patch literal 2917 zcmdT`TTkOg6y~jQVw=nEB9=>ZYE%(db#BXLfrnPAwj>qp3#_QLMyjzV#EN5k?FpOo zu~pSreeJJ+R(7i+{R}{VAP0{-?1riy}U~(crJW}pEcq`c^-;Smr4surCBH!i*p>H7I;ml zAp{g!VNh^9({OM_g0SE=3Vvf-+iKa4RiGrKg*Is#W~ljw*)X}(QmnwpM{)nP_quD1r?MpTg@#G*6M-X^cDE#83TmXmT6mgZobu_go(OD z$d?zAbIXi&Q7bNLrE+}Q^QqmmzcVQFWrwIX-luhZ;HppxZu_QZ;r~~48+lkBxE=-4 zwnGZG3o(b%Vm_VD*)_-+t_8U*ujN`k%*2WlIci#foEN-(#P`hl(o+8nkn7KA!~Sw1 z4QzK?b4VEaa19oea#2xLHO5SMC> zXIPqp`c(8w=u3F#2XJi%J)*ruYKCK@j~V7sGXr8!qM4pcNt?p-3p@zQ{y}v3`aoBv ze^TJZ4lyZuEke_15G{F{pPPF!zX|i3>bsCJmexkJTmp=xkUFR^w7#d}CX|^ms{nLw z5$5&l!|>N1U;nwUE8V~L501F|nC1m0Kc5r=!B{Z92?p;C&2}BzB^qh_m{}E)__+0 z;~umLOIw3niv&JmWr)$_QAM2)dt=dLFIDY+%vZ;3)r+Q1HuiqbNKv&btw)b`U#dNM zaHSWWMp-#4O^s)V9!n=1zx|PsDx=cbxjd}9vZU+spit5E>5+`?Rz_v~mZfSpBgt~L zE38Mu^3e0W?|Z`>@r(Qi{jx+lw$%pSZx@S;Vl{DKQhfiGaW0gAPXjh%!11=(K>hR| zprq-S_;(qYQv5i?g<5SB7H*gtO}mZ5`Ep_;g&{>#7>>!_u`J>8q@u1*kBg{djP0Ce zQn-0mQFR?>)niepWKpj>fd?}fFG;}F8C!`0#t+SyWbK?O4BOCwHgggyybxBtBB99E zZJd22uB}#su(Jt^H?R-uUcjd3m3eo`91|8ZpAa*ZaU_l@z^zlpJ7z6PnK3-Wk}L_h zI^~HMbQf7?WD&n(D_KN~iq=n22T(?mqW1_WVZb@-n_^B}extj>8!UqwScONzN>5kD zj^&{br%t3(U70wO&UGa__-4E}DXe6NMR|B*@As7Ww;)zBx>D`x?pid`d%pL}n-OO9 zh+942R-=QvKgfd*#P#Um?rJKoFw^$ySU$`hpJ^f9lxh^}w#Hs%CUT;x~`@ yMuqjpx8sN#VI8!m{gjpG=CB}>oH3;!J{MmK@ literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/rijndael.el b/xemacs-packages/lisp/ecrypto/rijndael.el new file mode 100644 index 00000000..019983a3 --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/rijndael.el @@ -0,0 +1,843 @@ +;;; rijndael.el --- Rijndael (AES) block cipher implementation +;; Copyright (C) 2001 Simon Josefsson + +;; Author: Simon Josefsson +;; Keywords: rijndael aes block cipher symmetric encryption cryptography + +;; This software is provided as-is, without express or implied +;; warranty. Permission to use, copy, modify, distribute or sell this +;; software, without fee, for any purpose and by any individual or +;; organization, is hereby granted, provided that the above copyright +;; notice and this paragraph appear in all copies. + +;;; Commentary: + +;; This is a implementation of the Rijndael block cipher algorithm in +;; Emacs Lisp. Rijndael has been chosen as the Advanced Encryption +;; Standard (AES) by NIST. +;; +;; This package also have functionality to generate (some of) NIST's +;; Rijndael test vectors. However, they will take a very long time to +;; generate in elisp. You can customize `rijndael-monte-carlo-limit' +;; from the default of 10,000 into something more sensible as, say, 1 +;; to make it faster. It is also possible to customize the loop +;; length defined by `rijndael-monte-carlo-loop' from the default 400. +;; Of course, you need to modify the reference implementation as well +;; if you want to make useful comparisons of the test vectors. +;; +;; Rijndael home page is at: +;; http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ +;; +;; Any updated releases of this file will be located at: +;; http://josefsson.org/aes/ + +;;; Instructions: + +;; Call functions in Emacs Lisp programs, or use this package +;; interactively in the *scratch* buffer in emacs. +;; +;; Here's how you could do a simple encryption interactively (press +;; C-j to evaluate each line): +;; +;; (setq key (rijndael-make-key 128 (rijndael-hexstring-to-bitstring +;; "00000000000000000000000000000000"))) +;; +;; (setq data (rijndael-hexstring-to-bitstring +;; "00000000000000000000000000000000")) +;; +;; (rijndael-bitstring-to-hexstring +;; (rijndael-block-encrypt data key 'ecb 128)) +;; +;; Or more compact as: +;; +;; (rijndael-bitstring-to-hexstring +;; (rijndael-block-encrypt +;; (rijndael-hexstring-to-bitstring "00000000000000000000000000000000") +;; (rijndael-make-key 128 (rijndael-hexstring-to-bitstring +;; "00000000000000000000000000000000")) +;; 'ecb 128)) +;; +;; For reference, correct output is "66e94bd4ef8a2c3b884cfa59ca342b2e". +;; +;; NB! `data' will be destructively modified. + +;;; Todo: + +;; Other modes than ECB. + +;;; Revision history: + +;; 2001-03-31 Posted to gnu.emacs.sources. +;; 2001-04-04 Ported to (X)Emacs 19. +;; 2001-05-10 Supports 160 and 224 key and block sizes. +;; 2001-09-27 Posted to gnu.emacs.sources. + + +;;; Code: + +;; User variables: + +(eval-and-compile + ;; Provide dummy customize functions for emacsen that doesn't have them. + (if (not (and (or (featurep 'custom) (load "custom" t)) + (fboundp 'defcustom) (fboundp 'defgroup))) + (progn + (if (not (fboundp 'defcustom)) + (defmacro defcustom (var value doc &rest args) + (list 'defvar var value doc))) + (if (not (fboundp 'defgroup)) + (defmacro defgroup (&rest args)))))) + +(defgroup rijndael nil + "Rijndael cryptographic functions") + +(defcustom rijndael-monte-carlo-limit 10000 + "How many iterations to do in the Monte-Carlo tests. +NIST uses 10000 (the default), but this will be very slow, so you may +change this to a lower value (like, say, 1). Of course, you must +modify the Rijndael reference implementation to be able to compare the +output." + :group 'rijndael + :type 'integer) + +(defcustom rijndael-monte-carlo-loop 400 + "How many iterations to do in the Monte-Carlo tests. +NIST uses 400 (the default), but this will be very slow, so you may +change this to a lower value (like, say, 1). Of course, you must +modify the Rijndael reference implementation to be able to compare the +output." + :group 'rijndael + :type 'integer) + + +;; Internal constants: + +(defconst rijndael-Logtable + [ 0 0 25 1 50 2 26 198 75 199 27 104 51 238 223 3 + 100 4 224 14 52 141 129 239 76 113 8 200 248 105 28 193 + 125 194 29 181 249 185 39 106 77 228 166 114 154 201 9 120 + 101 47 138 5 33 15 225 36 18 240 130 69 53 147 218 142 + 150 143 219 189 54 208 206 148 19 92 210 241 64 70 131 56 + 102 221 253 48 191 6 139 98 179 37 226 152 34 136 145 16 + 126 110 72 195 163 182 30 66 58 107 40 84 250 133 61 186 + 43 121 10 21 155 159 94 202 78 212 172 229 243 115 167 87 + 175 88 168 80 244 234 214 116 79 174 233 213 231 230 173 232 + 44 215 117 122 235 22 11 245 89 203 95 176 156 169 81 160 + 127 12 246 111 23 196 73 236 216 67 31 45 164 118 123 183 + 204 187 62 90 251 96 177 134 59 82 161 108 170 85 41 157 + 151 178 135 144 97 190 220 252 188 149 207 205 55 63 91 209 + 83 57 132 60 65 162 109 71 20 42 158 93 86 242 211 171 + 68 17 146 217 35 32 46 137 180 124 184 38 119 153 227 165 + 103 74 237 222 197 49 254 24 13 99 140 128 192 247 112 7] + "Multiplication in GF(2^8) lookup table.") + +(defconst rijndael-Alogtable + [ 1 3 5 15 17 51 85 255 26 46 114 150 161 248 19 53 + 95 225 56 72 216 115 149 164 247 2 6 10 30 34 102 170 + 229 52 92 228 55 89 235 38 106 190 217 112 144 171 230 49 + 83 245 4 12 20 60 68 204 79 209 104 184 211 110 178 205 + 76 212 103 169 224 59 77 215 98 166 241 8 24 40 120 136 + 131 158 185 208 107 189 220 127 129 152 179 206 73 219 118 154 + 181 196 87 249 16 48 80 240 11 29 39 105 187 214 97 163 + 254 25 43 125 135 146 173 236 47 113 147 174 233 32 96 160 + 251 22 58 78 210 109 183 194 93 231 50 86 250 21 63 65 + 195 94 226 61 71 201 64 192 91 237 44 116 156 191 218 117 + 159 186 213 100 172 239 42 126 130 157 188 223 122 142 137 128 + 155 182 193 88 232 35 101 175 234 37 111 177 200 67 197 84 + 252 31 33 99 165 244 7 9 27 45 119 153 176 203 70 202 + 69 207 74 222 121 139 134 145 168 227 62 66 198 81 243 14 + 18 54 90 238 41 123 141 140 143 138 133 148 167 242 13 23 + 57 75 221 124 132 151 162 253 28 36 108 180 199 82 246 1] + "Multiplication in GF(2^8) lookup table.") + +(defconst rijndael-S + [ 99 124 119 123 242 107 111 197 48 1 103 43 254 215 171 118 + 202 130 201 125 250 89 71 240 173 212 162 175 156 164 114 192 + 183 253 147 38 54 63 247 204 52 165 229 241 113 216 49 21 + 4 199 35 195 24 150 5 154 7 18 128 226 235 39 178 117 + 9 131 44 26 27 110 90 160 82 59 214 179 41 227 47 132 + 83 209 0 237 32 252 177 91 106 203 190 57 74 76 88 207 + 208 239 170 251 67 77 51 133 69 249 2 127 80 60 159 168 + 81 163 64 143 146 157 56 245 188 182 218 33 16 255 243 210 + 205 12 19 236 95 151 68 23 196 167 126 61 100 93 25 115 + 96 129 79 220 34 42 144 136 70 238 184 20 222 94 11 219 + 224 50 58 10 73 6 36 92 194 211 172 98 145 149 228 121 + 231 200 55 109 141 213 78 169 108 86 244 234 101 122 174 8 + 186 120 37 46 28 166 180 198 232 221 116 31 75 189 139 138 + 112 62 181 102 72 3 246 14 97 53 87 185 134 193 29 158 + 225 248 152 17 105 217 142 148 155 30 135 233 206 85 40 223 + 140 161 137 13 191 230 66 104 65 153 45 15 176 84 187 22] + "Rijndael S-box.") + +(defconst rijndael-Si + [ 82 9 106 213 48 54 165 56 191 64 163 158 129 243 215 251 + 124 227 57 130 155 47 255 135 52 142 67 68 196 222 233 203 + 84 123 148 50 166 194 35 61 238 76 149 11 66 250 195 78 + 8 46 161 102 40 217 36 178 118 91 162 73 109 139 209 37 + 114 248 246 100 134 104 152 22 212 164 92 204 93 101 182 146 + 108 112 72 80 253 237 185 218 94 21 70 87 167 141 157 132 + 144 216 171 0 140 188 211 10 247 228 88 5 184 179 69 6 + 208 44 30 143 202 63 15 2 193 175 189 3 1 19 138 107 + 58 145 17 65 79 103 220 234 151 242 207 206 240 180 230 115 + 150 172 116 34 231 173 53 133 226 249 55 232 28 117 223 110 + 71 241 26 113 29 41 197 137 111 183 98 14 170 24 190 27 + 252 86 62 75 198 210 121 32 154 219 192 254 120 205 90 244 + 31 221 168 51 136 7 199 49 177 18 16 89 39 128 236 95 + 96 81 127 169 25 181 74 13 45 229 122 159 147 201 156 239 + 160 224 59 77 174 42 245 176 200 235 187 60 131 83 153 97 + 23 43 4 126 186 119 214 38 225 105 20 99 85 33 12 125] + "Rijndael inverted S-box.") + +(defconst rijndael-rcon [ ?\x01 ?\x02 ?\x04 ?\x08 ?\x10 ?\x20 ?\x40 ?\x80 + ?\x1b ?\x36 ?\x6c ?\xd8 ?\xab ?\x4d ?\x9a ?\x2f + ?\x5e ?\xbc ?\x63 ?\xc6 ?\x97 ?\x35 ?\x6a ?\xd4 + ?\xb3 ?\x7d ?\xfa ?\xef ?\xc5 ?\x91] + "Rijndael round constants used in key scheduling.") + +(defconst rijndael-shifts [[[0 0] + [1 3] + [2 2] + [3 1]] + + [[0 0] + [1 4] + [2 3] + [3 2]] + + [[0 0] + [1 5] + [2 4] + [3 3]] + + [[0 0] + [1 6] + [2 5] + [4 3]] + + [[0 0] + [1 7] + [3 5] + [4 4]]] + "Rijndael shift offsets. +Element M is used when blocksizes match M=Nb-4. +Element N inside a shift amount for each blocksize corresponds with +the row to shift. +The first element O1 of each row corresponds with encryption offset, +the second element O2 to decryption offset. (O2 inverse of O1 under mod Nb.)") + +(defconst rijndael-maxbc (/ 256 32) + "Rijndael maximum size of data blocks.") + +(defconst rijndael-maxkc (/ 256 32) + "Rijndael maximum size of key blocks.") + +(defconst rijndael-maxrounds 14 + "Rijndael maximum number of rounds.") + +(defconst rijndael-hex-alist + '((?0 . 0) (?a . 10) (?A . 10) + (?1 . 1) (?b . 11) (?B . 11) + (?2 . 2) (?c . 12) (?C . 12) + (?3 . 3) (?d . 13) (?D . 13) + (?4 . 4) (?e . 14) (?E . 14) + (?5 . 5) (?f . 15) (?F . 15) + (?6 . 6) + (?7 . 7) + (?8 . 8) + (?9 . 9)) + "Hex table for use in base conversions.") + + +;; Basic low-level cryptograhic primitives: + +(defsubst rijndael-mul (a b) + "Rijndael MUL primitive. +Multiply two elements of GF(2^m). +needed for MixColumn and InvMixColumn." + (if (and (not (= a 0)) + (not (= b 0))) + (aref rijndael-Alogtable (% (+ (aref rijndael-Logtable a) + (aref rijndael-Logtable b)) + 255)) + 0)) + +(defsubst rijndael-key-addition (a rk bc) + "Rijndael keyAddition primitive. +Exor corresponding text input and round key input bytes." + (let ((i 0) j) + (while (< i 4) + (setq j 0) + (while (< j bc) + (aset (aref a i) j + (logxor (aref (aref a i) j) + (aref (aref rk i) j))) + (setq j (1+ j))) + (setq i (1+ i))))) + +(defsubst rijndael-shift-row (a d bc) + "Rijndael ShiftRow primitive. +Row 0 remains unchanged. +The other three rows are shifted a variable amount." + (let (i j (tmp (make-vector rijndael-maxbc 0))) + (setq i 1) + (while (< i 4) + (setq j 0) + (while (< j bc) + (aset tmp j + (aref (aref a i) + (% (+ j (aref (aref (aref rijndael-shifts + (- bc 4)) + i) + d)) + bc))) + (setq j (1+ j))) + (setq j 0) + (while (< j bc) + (aset (aref a i) j (aref tmp j)) + (setq j (1+ j))) + (setq i (1+ i))))) + +(defsubst rijndael-substitution (a box bc) + "Rijndael substitution primitive. +Replace every byte of the input by the byte at that place +in the nonlinear S-box." + (let ((i 0) j) + (while (< i 4) + (setq j 0) + (while (< j bc) + (aset (aref a i) j (aref box (aref (aref a i) j))) + (setq j (1+ j))) + (setq i (1+ i))))) + +(defsubst rijndael-mix-column (a bc) + "Rijndael MixColumn primitive. +Mix the four bytes of every column in a linear way." + (let ((b (make-vector 4 0)) i j) + ;; init b + (setq i 0) + (while (< i 4) + (aset b i (make-vector rijndael-maxbc 0)) + (setq i (1+ i))) + ;; do it + (setq j 0) + (while (< j bc) + (setq i 0) + (while (< i 4) + (aset (aref b i) + j + (logxor (rijndael-mul 2 (aref (aref a i) j)) + (rijndael-mul 3 (aref (aref a (% (+ i 1) 4)) j)) + (aref (aref a (% (+ i 2) 4)) j) + (aref (aref a (% (+ i 3) 4)) j))) + (setq i (1+ i))) + (setq j (1+ j))) + ;; copy b back into a + (setq i 0) + (while (< i 4) + (setq j 0) + (while (< j bc) + (aset (aref a i) j (aref (aref b i) j)) + (setq j (1+ j))) + (setq i (1+ i))))) + +(defsubst rijndael-inv-mix-column (a bc) + "Rijndael inverted MixColumn primitive. +Mix the four bytes of every column in a linear way. +This is the opposite operation of Mixcolumn." + (let ((b (make-vector 4 0)) i j) + ;; init b + (setq i 0) + (while (< i 4) + (aset b i (make-vector rijndael-maxbc 0)) + (setq i (1+ i))) + ;; do it + (setq j 0) + (while (< j bc) + (setq i 0) + (while (< i 4) + (aset (aref b i) + j + (logxor (rijndael-mul ?\x0E (aref (aref a i) j)) + (rijndael-mul ?\x0B (aref (aref a (% (+ i 1) 4)) j)) + (rijndael-mul ?\x0D (aref (aref a (% (+ i 2) 4)) j)) + (rijndael-mul ?\x09 (aref (aref a (% (+ i 3) 4)) j)))) + (setq i (1+ i))) + (setq j (1+ j))) + ;; copy b back into a + (setq i 0) + (while (< i 4) + (setq j 0) + (while (< j bc) + (aset (aref a i) j (aref (aref b i) j)) + (setq j (1+ j))) + (setq i (1+ i))))) + + +;; Internal functions: + +(defun rijndael-bc (blockBits) + "Determine BC given block size." + (if (or (< blockBits 128) (> blockBits 256)) + (error "Invalid block size %d bits" blockBits) + (/ blockBits 32))) + +(defun rijndael-rounds (keyBits blockBits) + "Determine Rijndael rounds given key and block sizes." + (if (or (< keyBits 128) (> keyBits 256) (< blockBits 128) (> blockBits 256)) + (error "Invalid key/block size combination (key size %d block size %d)" + keyBits blockBits) + (+ (/ (max keyBits blockBits) 32) 6))) + +(defun rijndael-print-key-schedule (key-schedule) + (let (i j k str) + (setq i 0) + (while (< i (1+ rijndael-maxrounds)) + (setq j 0) + (while (< j 4) + (setq k 0) + (while (< k rijndael-maxbc) + (setq str (concat str (format "%3d " + (aref (aref (aref key-schedule i) + j) + k)))) + (setq k (1+ k))) + (setq str (concat str "\n")) + (setq j (1+ j))) + (setq str (concat str "\n")) + (setq i (1+ i))) + (setq str (concat str "\n")))) + +(defun rijndael-key-schedule (k keyBits blockBits) + "Rijndael KeySchedule function (internal). +Calculate the necessary round keys. +The number of calculations depends on keyBits and blockBits." + (let ((rconpointer 0) i j T + (kc (rijndael-bc keyBits)) + (bc (rijndael-bc blockBits)) + (rounds (rijndael-rounds keyBits blockBits)) + (tk (make-vector 4 0)) + (W (make-vector (1+ rijndael-maxrounds) 0)) + (mid 4)) + ;; init tk + (setq i 0) + (while (< i 4) + (aset tk i (make-vector rijndael-maxkc 0)) + (setq i (1+ i))) + ;; init W + (setq i 0) + (while (< i (1+ rijndael-maxrounds)) + (aset W i (make-vector 4 0)) + (setq j 0) + (while (< j 4) + (aset (aref W i) j (make-vector rijndael-maxbc 0)) + (setq j (1+ j))) + (setq i (1+ i))) + ;; start + (setq j 0) + (while (< j kc) + (setq i 0) + (while (< i 4) + (aset (aref tk i) j + (aref (aref k i) j)) + (setq i (1+ i))) + (setq j (1+ j))) + ;; copy values into round key array + (setq j 0 + T 0) + (while (and (< j kc) (< T (* (1+ rounds) bc))) + (setq i 0) + (while (< i 4) + (aset (aref (aref W (/ T bc)) i) (% T bc) + (aref (aref tk i) j)) + (setq i (1+ i))) + (setq j (1+ j)) + (setq T (1+ T))) + ;; while not enough round key material calculated + (while (< T (* (1+ rounds) bc)) + ;; calculate new values + (setq i 0) + (while (< i 4) + (aset (aref tk i) 0 + (logxor (aref (aref tk i) 0) + (aref rijndael-S + (aref (aref tk (% (1+ i) 4)) (1- kc))))) + (setq i (1+ i))) + (aset (aref tk 0) 0 + (logxor (aref (aref tk 0) 0) + (aref rijndael-rcon rconpointer))) + (setq rconpointer (1+ rconpointer)) + (setq j 1) + (if (<= kc 6) + (while (< j kc) + (setq i 0) + (while (< i mid) + (aset (aref tk i) j + (logxor (aref (aref tk i) j) + (aref (aref tk i) (1- j)))) + (setq i (1+ i))) + (setq j (1+ j))) + (while (< j mid) + (setq i 0) + (while (< i 4) + (aset (aref tk i) j + (logxor (aref (aref tk i) j) + (aref (aref tk i) (1- j)))) + (setq i (1+ i))) + (setq j (1+ j))) + (setq i 0) + (while (< i 4) + (aset (aref tk i) mid + (logxor (aref (aref tk i) mid) + (aref rijndael-S (aref (aref tk i) (1- mid))))) + (setq i (1+ i))) + (setq j (1+ mid) i 0) + (while (< j kc) + (setq i 0) + (while (< i mid) + (aset (aref tk i) j + (logxor (aref (aref tk i) j) + (aref (aref tk i) (1- j)))) + (setq i (1+ i))) + (setq j (1+ j)))) + ;; copy values into round key array + (setq j 0) + (while (and (< j kc) (< T (* (1+ rounds) bc))) + (setq i 0) + (while (< i 4) + (aset (aref (aref W (/ T bc)) i) (% T bc) + (aref (aref tk i) j)) + (setq i (1+ i))) + (setq j (1+ j)) + (setq T (1+ T)))) + W)) + +(defun rijndael-encrypt (a keyBits blockBits rk &optional rounds) + "Rijndael block encryption (internal). +Encryption of one block. If optional argument rounds is non-null, +encrypt only a certain number of rounds (for debugging only)." + (let ((r 1) + (bc (rijndael-bc blockBits)) + (ROUNDS (rijndael-rounds keyBits blockBits))) + ;; make number of rounds sane + (if (or (null rounds) (> rounds ROUNDS)) + (setq rounds ROUNDS)) + ;; begin with a key addition + (rijndael-key-addition a (aref rk 0) bc) + ;; ROUNDS-1 ordinary rounds + (while (and (<= r rounds) (< r ROUNDS)) + (rijndael-substitution a rijndael-S bc) + (rijndael-shift-row a 0 bc) + (rijndael-mix-column a bc) + (rijndael-key-addition a (aref rk r) bc) + (setq r (1+ r))) + ;; Last round is special: there is no MixColumn + (if (= rounds ROUNDS) + (progn + (rijndael-substitution a rijndael-S bc) + (rijndael-shift-row a 0 bc) + (rijndael-key-addition a (aref rk rounds) bc))))) + +(defun rijndael-decrypt (a keyBits blockBits rk &optional rounds) + "Rijndael block decryption (internal). +Decryption of one block. If optional argument rounds is non-null, +decrypt only a certain number of rounds (for debugging only)." + (let* ((bc (rijndael-bc blockBits)) + (ROUNDS (rijndael-rounds keyBits blockBits)) + (r (1- ROUNDS))) + ;; make number of rounds sane + (if (or (null rounds) (> rounds ROUNDS)) + (setq rounds 0)) + ;; First the special round: + ;; without InvMixColumn + ;; with extra KeyAddition + (rijndael-key-addition a (aref rk ROUNDS) bc) + (rijndael-substitution a rijndael-Si bc) + (rijndael-shift-row a 1 bc) + (while (> r rounds) + (rijndael-key-addition a (aref rk r) bc) + (rijndael-inv-mix-column a bc) + (rijndael-substitution a rijndael-Si bc) + (rijndael-shift-row a 1 bc) + (setq r (1- r))) + ;; End with the extra key addition + (if (= rounds 0) + (rijndael-key-addition a (aref rk 0) bc)))) + + +;; Rijndael API functions: + +(defun rijndael-make-key (blockbits keymaterial) + "Generate Key Schedule given keying material KEYMATERIAL. +KEYMATERIAL must be of length multiple of 32 bits. +BLOCKBITS is size of blocks in bits (valid values 128, 160, 192, 224 and 256)." + (let ((k (make-vector 4 0)) i + (keybits (* (length keymaterial) 8))) + ;; init k + (setq i 0) + (while (< i 4) + (aset k i (make-vector rijndael-maxkc 0)) + (setq i (1+ i))) + (setq i 0) + (while (< i (/ keybits 8)) + (aset (aref k (% i 4)) (/ i 4) (aref (vconcat keymaterial) i)) + (setq i (1+ i))) + (list keybits keymaterial (rijndael-key-schedule k keybits blockbits)))) + +(defun rijndael-block-encrypt (data key mode blockbits &optional iv) + "Perform Rijndael encryption of DATA with key KEY. +DATA is a vector with data to encrypt (the block). +KEY is a Rijndael Key Schedule (see `rijndael-make-key'). +MODE is a symbol, `ecb', `cbc' or `cfb1', for the encryption mode to use. +BLOCKBITS is size of blocks in bits (valid values 128, 160, 192, 224 and 256). +Optional variable IV is a string containing initialization vectors." + (let ((numBlocks (/ (length data) (/ blockbits 8))) + (blk (make-vector 4 0)) + i j l) + ;; init blk + (setq i 0) + (while (< i 4) + (aset blk i (make-vector rijndael-maxbc 0)) + (setq i (1+ i))) + (cond ((eq mode 'ecb) + (setq i 0) + (while (< i numBlocks) + (setq j 0) + (while (< j (/ blockbits 32)) + (setq l 0) + (while (< l 4) + (aset (aref blk l) j (aref data (+ (* (/ blockbits 8) i) + (* 4 j) + l))) + (setq l (1+ l))) + (setq j (1+ j))) + (rijndael-encrypt blk (nth 0 key) blockbits (nth 2 key)) + (setq j 0) + (while (< j (/ blockbits 32)) + (setq l 0) + (while (< l 4) + (aset data (+ (* (/ blockbits 8) i) + (* 4 j) + l) + (aref (aref blk l) j)) + (setq l (1+ l))) + (setq j (1+ j))) + (setq i (1+ i)))) + (t + (error "Unknown encryption mode: %s" mode))) + data)) + +(defun rijndael-block-decrypt (data key mode blockbits &optional iv) + "Perform Rijndael encryption of DATA with key KEY. +DATA is a vector with data to encrypt (the block). +KEY is a Rijndael Key Schedule (see `rijndael-make-key'). +MODE is a symbol, `ecb', `cbc' or `cfb1', for the decryption mode to use. +BLOCKBITS is size of block in bits (valid values 128, 160, 192, 224 and 256). +Optional variable IV is a string containing initialization vectors." + (let ((numBlocks (/ (length data) (/ blockbits 8))) + (blk (make-vector 4 0)) + i j l) + ;; init blk + (setq i 0) + (while (< i 4) + (aset blk i (make-vector rijndael-maxbc 0)) + (setq i (1+ i))) + (cond ((eq mode 'ecb) + (setq i 0) + (while (< i numBlocks) + (setq j 0) + (while (< j (/ blockbits 32)) + (setq l 0) + (while (< l 4) + (aset (aref blk l) j (aref data (+ (* (/ blockbits 8) i) + (* 4 j) + l))) + (setq l (1+ l))) + (setq j (1+ j))) + (rijndael-decrypt blk (nth 0 key) blockbits (nth 2 key)) + (setq j 0) + (while (< j (/ blockbits 32)) + (setq l 0) + (while (< l 4) + (aset data (+ (* (/ blockbits 8) i) + (* 4 j) + l) + (aref (aref blk l) j)) + (setq l (1+ l))) + (setq j (1+ j))) + (setq i (1+ i)))) + (t + (error "Unknown decryption mode: %s" mode))) + data)) + + +;; Conversion functions: + +(defun rijndael-hex-to-int (str) + (if str + (if (listp str) + (+ (* 16 (rijndael-hex-to-int (cdr str))) + (cdr (assoc (car str) rijndael-hex-alist))) + (rijndael-hex-to-int (reverse (append str nil)))) + 0)) + +(defun rijndael-hexstring-to-bitstring (str) + (let (out) + (while (< 0 (length str)) + (setq out (cons (rijndael-hex-to-int (substring str -2)) out)) + (setq str (substring str 0 -2))) + (concat out))) + +(defun rijndael-vector-to-hexstring (vec) + (mapconcat (lambda (el) + (format "%02x" el)) + vec + "")) + +(defun rijndael-vector-to-bitstring (vec) + (rijndael-hexstring-to-bitstring (rijndael-vector-to-hexstring vec))) + +(defun rijndael-bitstring-to-vector (str) + (let ((out (make-vector (length str) 0)) + (i (1- (length str)))) + (while (< 0 (length str)) + (aset out i (string-to-char (substring str -1))) + (setq i (1- i)) + (setq str (substring str 0 -1))) + out)) + +(defun rijndael-bitstring-to-hexstring (str) + (let ((out "")) + (while (< 0 (length str)) + (setq out (format "%02x%s" (string-to-char (substring str -1)) out)) + (setq str (substring str 0 -1))) + out)) + + +;; NIST test value generator + +(defun rijndael-nist () + "Generate NIST test values. +The output is to be compared with the NIST tabulated values." + (interactive) + (switch-to-buffer (generate-new-buffer "*NIST Rijndael test values")) + (erase-buffer) + (insert "\n\n\nElectronic Codebook (ECB) Mode - ENCRYPTION\n") + ;; ECB encrypt keysize 128 + (rijndael-nist-ecb-mct + "00000000000000000000000000000000" 128 + "00000000000000000000000000000000" 128 'encrypt) + ;; ECB encrypt keysize 160 + (rijndael-nist-ecb-mct + "0000000000000000000000000000000000000000" 160 + "00000000000000000000000000000000" 128 'encrypt) + ;; ECB encrypt keysize 192 + (rijndael-nist-ecb-mct + "000000000000000000000000000000000000000000000000" 192 + "00000000000000000000000000000000" 128 'encrypt) + ;; ECB encrypt keysize 224 + (rijndael-nist-ecb-mct + "00000000000000000000000000000000000000000000000000000000" 224 + "00000000000000000000000000000000" 128 'encrypt) + ;; ECB encrypt keysize 256 + (rijndael-nist-ecb-mct + "0000000000000000000000000000000000000000000000000000000000000000" 256 + "00000000000000000000000000000000" 128 'encrypt) + (insert "\n\n\nElectronic Codebook (ECB) Mode - DECRYPTION\n") + ;; ECB decrypt keysize 128 + (rijndael-nist-ecb-mct + "00000000000000000000000000000000" 128 + "00000000000000000000000000000000" 128 'decrypt) + ;; ECB decrypt keysize 160 + (rijndael-nist-ecb-mct + "0000000000000000000000000000000000000000" 160 + "00000000000000000000000000000000" 128 'decrypt) + ;; ECB decrypt keysize 192 + (rijndael-nist-ecb-mct + "000000000000000000000000000000000000000000000000" 192 + "00000000000000000000000000000000" 128 'decrypt) + ;; ECB decrypt keysize 224 + (rijndael-nist-ecb-mct + "00000000000000000000000000000000000000000000000000000000" 224 + "00000000000000000000000000000000" 128 'decrypt) + ;; ECB decrypt keysize 256 + (rijndael-nist-ecb-mct + "0000000000000000000000000000000000000000000000000000000000000000" 256 + "00000000000000000000000000000000" 128 'decrypt) + (message "NIST Rijndael tables generation...done")) + +(defun rijndael-nist-ecb-mct (initKey keyLength initBlock blockLength dir) + (let ((binKey (rijndael-bitstring-to-vector + (rijndael-hexstring-to-bitstring initKey))) + (outBlock (rijndael-hexstring-to-bitstring initBlock)) + (i 0) j keyInst inBlock) + (insert "\n=========================\n\n") + (insert (format "KEYSIZE=%d\n" keyLength)) + (while (< i rijndael-monte-carlo-loop) + (sit-for 0) + (insert (format "\nI=%d\n" i)) + (insert "KEY=" (rijndael-vector-to-hexstring binKey) "\n") + (setq keyInst (rijndael-make-key blockLength + (rijndael-vector-to-bitstring binKey))) + (insert (if (eq dir 'encrypt) "PT=" "CT=") + (rijndael-bitstring-to-hexstring outBlock) "\n") + (setq j 0) + (while (< j rijndael-monte-carlo-limit) + (if (eq (% j 100) 0) + (message (concat "Rijndael NIST ECB MCT %sion (%db keys, " + "%db blocks) loop %d of %d%s") + dir keyLength blockLength i + rijndael-monte-carlo-loop + (if (> rijndael-monte-carlo-limit 1) + (format " iteration %d of %d" j + rijndael-monte-carlo-limit) + ""))) + (setq inBlock (copy-sequence outBlock)) + (if (eq dir 'encrypt) + (rijndael-block-encrypt outBlock keyInst 'ecb blockLength) + (rijndael-block-decrypt outBlock keyInst 'ecb blockLength)) + (setq j (1+ j))) + (insert (if (eq dir 'encrypt) "CT=" "PT=") + (rijndael-bitstring-to-hexstring outBlock) "\n") + (cond ((eq keyLength 128) + (setq j 0) + (while (< j (/ 128 8)) + (aset binKey j (logxor (aref binKey j) + (aref + (rijndael-bitstring-to-vector outBlock) + j))) + (setq j (1+ j)))) + ((eq keyLength 192) + (setq j 0) + (while (< j (/ 64 8)) + (aset binKey j (logxor (aref binKey j) + (aref + (rijndael-bitstring-to-vector inBlock) + (+ j (/ 64 8))))) + (setq j (1+ j))) + (setq j 0) + (while (< j (/ 128 8)) + (aset binKey (+ j (/ 64 8)) + (logxor (aref binKey (+ j (/ 64 8))) + (aref (rijndael-bitstring-to-vector outBlock) j))) + (setq j (1+ j)))) + ((eq keyLength 256) + (setq j 0) + (while (< j (/ 128 8)) + (aset binKey j (logxor (aref binKey j) + (aref + (rijndael-bitstring-to-vector inBlock) + j))) + (setq j (1+ j))) + (setq j 0) + (while (< j (/ 128 8)) + (aset binKey (+ j (/ 128 8)) + (logxor (aref binKey j) + (aref + (rijndael-bitstring-to-vector outBlock) + j))) + (setq j (1+ j))))) + (setq i (1+ i))))) + +(provide 'rijndael) + +;; rijndael.el ends here diff --git a/xemacs-packages/lisp/ecrypto/rijndael.elc b/xemacs-packages/lisp/ecrypto/rijndael.elc new file mode 100644 index 0000000000000000000000000000000000000000..2e09cddd513f6295bbc0cebb4e22775adb9b9590 GIT binary patch literal 19107 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ecrypto/sha1.el b/xemacs-packages/lisp/ecrypto/sha1.el new file mode 100644 index 00000000..e6332b5c --- /dev/null +++ b/xemacs-packages/lisp/ecrypto/sha1.el @@ -0,0 +1,442 @@ +;;; sha1.el --- SHA1 Secure Hash Algorithm in Emacs-Lisp + +;; Copyright (C) 1999, 2001, 2002, 2003, 2004, +;; 2005 Free Software Foundation, Inc. + +;; Author: Shuhei KOBAYASHI +;; Keywords: SHA1, FIPS 180-1 + +;; This file is part of FLIM (Faithful Library about Internet Message). + +;; This program 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 program 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 this program; 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 is implemented from the definition of SHA-1 in FIPS PUB +;; 180-1 (Federal Information Processing Standards Publication 180-1), +;; "Announcing the Standard for SECURE HASH STANDARD". +;; +;; (EXCEPTION; two optimizations taken from GnuPG/cipher/sha1.c) +;; +;; Test cases from FIPS PUB 180-1. +;; +;; (sha1 "abc") +;; => a9993e364706816aba3e25717850c26c9cd0d89d +;; +;; (sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") +;; => 84983e441c3bd26ebaae4aa1f95129e5e54670f1 +;; +;; (sha1 (make-string 1000000 ?a)) +;; => 34aa973cd4c4daa4f61eeb2bdbad27316534016f +;; +;; BUGS: +;; * It is assumed that length of input string is less than 2^29 bytes. +;; * It is caller's responsibility to make string (or region) unibyte. +;; +;; TODO: +;; * Rewrite from scratch! +;; This version is much faster than Keiichi Suzuki's another sha1.el, +;; but it is too dirty. + +;;; Code: + +(require 'hex-util) + +;;; +;;; external SHA1 function. +;;; + +(defgroup sha1 nil + "Elisp interface for SHA1 hash computation." + :group 'extensions) + +(defcustom sha1-maximum-internal-length 500 + "*Maximum length of message to use Lisp version of SHA1 function. +If message is longer than this, `sha1-program' is used instead. + +If this variable is set to 0, use external program only. +If this variable is set to nil, use internal function only." + :type 'integer + :group 'sha1) + +(defcustom sha1-program '("sha1sum") + "*Name of program to compute SHA1. +It must be a string \(program name\) or list of strings \(name and its args\)." + :type '(repeat string) + :group 'sha1) + +(defcustom sha1-use-external (condition-case () + (executable-find (car sha1-program)) + (error)) + "*Use external SHA1 program. +If this variable is set to nil, use internal function only." + :type 'boolean + :group 'sha1) + +(defun sha1-string-external (string &optional binary) + (let (prog args digest default-enable-multibyte-characters) + (if (consp sha1-program) + (setq prog (car sha1-program) + args (cdr sha1-program)) + (setq prog sha1-program + args nil)) + (with-temp-buffer + (insert string) + (apply (function call-process-region) + (point-min)(point-max) + prog t t nil args) + ;; SHA1 is 40 bytes long in hexadecimal form. + (setq digest (buffer-substring (point-min)(+ (point-min) 40)))) + (if binary + (decode-hex-string digest) + digest))) + +(defun sha1-region-external (beg end &optional binary) + (sha1-string-external (buffer-substring-no-properties beg end) binary)) + +;;; +;;; internal SHA1 function. +;;; + +(eval-when-compile + ;; optional second arg of string-to-number is new in v20. + (defconst sha1-K0-high 23170) ; (string-to-number "5A82" 16) + (defconst sha1-K0-low 31129) ; (string-to-number "7999" 16) + (defconst sha1-K1-high 28377) ; (string-to-number "6ED9" 16) + (defconst sha1-K1-low 60321) ; (string-to-number "EBA1" 16) + (defconst sha1-K2-high 36635) ; (string-to-number "8F1B" 16) + (defconst sha1-K2-low 48348) ; (string-to-number "BCDC" 16) + (defconst sha1-K3-high 51810) ; (string-to-number "CA62" 16) + (defconst sha1-K3-low 49622) ; (string-to-number "C1D6" 16) + +;;; original definition of sha1-F0. +;;; (defmacro sha1-F0 (B C D) +;;; (` (logior (logand (, B) (, C)) +;;; (logand (lognot (, B)) (, D))))) +;;; a little optimization from GnuPG/cipher/sha1.c. + (defmacro sha1-F0 (B C D) + (` (logxor (, D) (logand (, B) (logxor (, C) (, D)))))) + (defmacro sha1-F1 (B C D) + (` (logxor (, B) (, C) (, D)))) +;;; original definition of sha1-F2. +;;; (defmacro sha1-F2 (B C D) +;;; (` (logior (logand (, B) (, C)) +;;; (logand (, B) (, D)) +;;; (logand (, C) (, D))))) +;;; a little optimization from GnuPG/cipher/sha1.c. + (defmacro sha1-F2 (B C D) + (` (logior (logand (, B) (, C)) + (logand (, D) (logior (, B) (, C)))))) + (defmacro sha1-F3 (B C D) + (` (logxor (, B) (, C) (, D)))) + + (defmacro sha1-S1 (W-high W-low) + (` (let ((W-high (, W-high)) + (W-low (, W-low))) + (setq S1W-high (+ (% (* W-high 2) 65536) + (/ W-low (, (/ 65536 2))))) + (setq S1W-low (+ (/ W-high (, (/ 65536 2))) + (% (* W-low 2) 65536)))))) + (defmacro sha1-S5 (A-high A-low) + (` (progn + (setq S5A-high (+ (% (* (, A-high) 32) 65536) + (/ (, A-low) (, (/ 65536 32))))) + (setq S5A-low (+ (/ (, A-high) (, (/ 65536 32))) + (% (* (, A-low) 32) 65536)))))) + (defmacro sha1-S30 (B-high B-low) + (` (progn + (setq S30B-high (+ (/ (, B-high) 4) + (* (% (, B-low) 4) (, (/ 65536 4))))) + (setq S30B-low (+ (/ (, B-low) 4) + (* (% (, B-high) 4) (, (/ 65536 4)))))))) + + (defmacro sha1-OP (round) + (` (progn + (sha1-S5 sha1-A-high sha1-A-low) + (sha1-S30 sha1-B-high sha1-B-low) + (setq sha1-A-low (+ ((, (intern (format "sha1-F%d" round))) + sha1-B-low sha1-C-low sha1-D-low) + sha1-E-low + (, (symbol-value + (intern (format "sha1-K%d-low" round)))) + (aref block-low idx) + (progn + (setq sha1-E-low sha1-D-low) + (setq sha1-D-low sha1-C-low) + (setq sha1-C-low S30B-low) + (setq sha1-B-low sha1-A-low) + S5A-low))) + (setq carry (/ sha1-A-low 65536)) + (setq sha1-A-low (% sha1-A-low 65536)) + (setq sha1-A-high (% (+ ((, (intern (format "sha1-F%d" round))) + sha1-B-high sha1-C-high sha1-D-high) + sha1-E-high + (, (symbol-value + (intern (format "sha1-K%d-high" round)))) + (aref block-high idx) + (progn + (setq sha1-E-high sha1-D-high) + (setq sha1-D-high sha1-C-high) + (setq sha1-C-high S30B-high) + (setq sha1-B-high sha1-A-high) + S5A-high) + carry) + 65536))))) + + (defmacro sha1-add-to-H (H X) + (` (progn + (setq (, (intern (format "sha1-%s-low" H))) + (+ (, (intern (format "sha1-%s-low" H))) + (, (intern (format "sha1-%s-low" X))))) + (setq carry (/ (, (intern (format "sha1-%s-low" H))) 65536)) + (setq (, (intern (format "sha1-%s-low" H))) + (% (, (intern (format "sha1-%s-low" H))) 65536)) + (setq (, (intern (format "sha1-%s-high" H))) + (% (+ (, (intern (format "sha1-%s-high" H))) + (, (intern (format "sha1-%s-high" X))) + carry) + 65536))))) + ) + +;;; buffers (H0 H1 H2 H3 H4). +(defvar sha1-H0-high) +(defvar sha1-H0-low) +(defvar sha1-H1-high) +(defvar sha1-H1-low) +(defvar sha1-H2-high) +(defvar sha1-H2-low) +(defvar sha1-H3-high) +(defvar sha1-H3-low) +(defvar sha1-H4-high) +(defvar sha1-H4-low) + +(defun sha1-block (block-high block-low) + (let (;; step (c) --- initialize buffers (A B C D E). + (sha1-A-high sha1-H0-high) (sha1-A-low sha1-H0-low) + (sha1-B-high sha1-H1-high) (sha1-B-low sha1-H1-low) + (sha1-C-high sha1-H2-high) (sha1-C-low sha1-H2-low) + (sha1-D-high sha1-H3-high) (sha1-D-low sha1-H3-low) + (sha1-E-high sha1-H4-high) (sha1-E-low sha1-H4-low) + (idx 16)) + ;; step (b). + (let (;; temporary variables used in sha1-S1 macro. + S1W-high S1W-low) + (while (< idx 80) + (sha1-S1 (logxor (aref block-high (- idx 3)) + (aref block-high (- idx 8)) + (aref block-high (- idx 14)) + (aref block-high (- idx 16))) + (logxor (aref block-low (- idx 3)) + (aref block-low (- idx 8)) + (aref block-low (- idx 14)) + (aref block-low (- idx 16)))) + (aset block-high idx S1W-high) + (aset block-low idx S1W-low) + (setq idx (1+ idx)))) + ;; step (d). + (setq idx 0) + (let (;; temporary variables used in sha1-OP macro. + S5A-high S5A-low S30B-high S30B-low carry) + (while (< idx 20) (sha1-OP 0) (setq idx (1+ idx))) + (while (< idx 40) (sha1-OP 1) (setq idx (1+ idx))) + (while (< idx 60) (sha1-OP 2) (setq idx (1+ idx))) + (while (< idx 80) (sha1-OP 3) (setq idx (1+ idx)))) + ;; step (e). + (let (;; temporary variables used in sha1-add-to-H macro. + carry) + (sha1-add-to-H H0 A) + (sha1-add-to-H H1 B) + (sha1-add-to-H H2 C) + (sha1-add-to-H H3 D) + (sha1-add-to-H H4 E)))) + +(defun sha1-binary (string) + "Return the SHA1 of STRING in binary form." + (let (;; prepare buffers for a block. byte-length of block is 64. + ;; input block is split into two vectors. + ;; + ;; input block: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ... + ;; block-high: +-0-+ +-1-+ +-2-+ +-3-+ + ;; block-low: +-0-+ +-1-+ +-2-+ +-3-+ + ;; + ;; length of each vector is 80, and elements of each vector are + ;; 16bit integers. elements 0x10-0x4F of each vector are + ;; assigned later in `sha1-block'. + (block-high (eval-when-compile (make-vector 80 nil))) + (block-low (eval-when-compile (make-vector 80 nil)))) + (unwind-protect + (let* (;; byte-length of input string. + (len (length string)) + (lim (* (/ len 64) 64)) + (rem (% len 4)) + (idx 0)(pos 0)) + ;; initialize buffers (H0 H1 H2 H3 H4). + (setq sha1-H0-high 26437 ; (string-to-number "6745" 16) + sha1-H0-low 8961 ; (string-to-number "2301" 16) + sha1-H1-high 61389 ; (string-to-number "EFCD" 16) + sha1-H1-low 43913 ; (string-to-number "AB89" 16) + sha1-H2-high 39098 ; (string-to-number "98BA" 16) + sha1-H2-low 56574 ; (string-to-number "DCFE" 16) + sha1-H3-high 4146 ; (string-to-number "1032" 16) + sha1-H3-low 21622 ; (string-to-number "5476" 16) + sha1-H4-high 50130 ; (string-to-number "C3D2" 16) + sha1-H4-low 57840) ; (string-to-number "E1F0" 16) + ;; loop for each 64 bytes block. + (while (< pos lim) + ;; step (a). + (setq idx 0) + (while (< idx 16) + (aset block-high idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (setq pos (+ pos 2)) + (aset block-low idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (setq pos (+ pos 2)) + (setq idx (1+ idx))) + (sha1-block block-high block-low)) + ;; last block. + (if (prog1 + (< (- len lim) 56) + (setq lim (- len rem)) + (setq idx 0) + (while (< pos lim) + (aset block-high idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (setq pos (+ pos 2)) + (aset block-low idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (setq pos (+ pos 2)) + (setq idx (1+ idx))) + ;; this is the last (at most) 32bit word. + (cond + ((= rem 3) + (aset block-high idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (setq pos (+ pos 2)) + (aset block-low idx (+ (* (aref string pos) 256) + 128))) + ((= rem 2) + (aset block-high idx (+ (* (aref string pos) 256) + (aref string (1+ pos)))) + (aset block-low idx 32768)) + ((= rem 1) + (aset block-high idx (+ (* (aref string pos) 256) + 128)) + (aset block-low idx 0)) + (t ;; (= rem 0) + (aset block-high idx 32768) + (aset block-low idx 0))) + (setq idx (1+ idx)) + (while (< idx 16) + (aset block-high idx 0) + (aset block-low idx 0) + (setq idx (1+ idx)))) + ;; last block has enough room to write the length of string. + (progn + ;; write bit length of string to last 4 bytes of the block. + (aset block-low 15 (* (% len 8192) 8)) + (setq len (/ len 8192)) + (aset block-high 15 (% len 65536)) + ;; XXX: It is not practical to compute SHA1 of + ;; such a huge message on emacs. + ;; (setq len (/ len 65536)) ; for 64bit emacs. + ;; (aset block-low 14 (% len 65536)) + ;; (aset block-high 14 (/ len 65536)) + (sha1-block block-high block-low)) + ;; need one more block. + (sha1-block block-high block-low) + (fillarray block-high 0) + (fillarray block-low 0) + ;; write bit length of string to last 4 bytes of the block. + (aset block-low 15 (* (% len 8192) 8)) + (setq len (/ len 8192)) + (aset block-high 15 (% len 65536)) + ;; XXX: It is not practical to compute SHA1 of + ;; such a huge message on emacs. + ;; (setq len (/ len 65536)) ; for 64bit emacs. + ;; (aset block-low 14 (% len 65536)) + ;; (aset block-high 14 (/ len 65536)) + (sha1-block block-high block-low)) + ;; make output string (in binary form). + (let ((result (make-string 20 0))) + (aset result 0 (/ sha1-H0-high 256)) + (aset result 1 (% sha1-H0-high 256)) + (aset result 2 (/ sha1-H0-low 256)) + (aset result 3 (% sha1-H0-low 256)) + (aset result 4 (/ sha1-H1-high 256)) + (aset result 5 (% sha1-H1-high 256)) + (aset result 6 (/ sha1-H1-low 256)) + (aset result 7 (% sha1-H1-low 256)) + (aset result 8 (/ sha1-H2-high 256)) + (aset result 9 (% sha1-H2-high 256)) + (aset result 10 (/ sha1-H2-low 256)) + (aset result 11 (% sha1-H2-low 256)) + (aset result 12 (/ sha1-H3-high 256)) + (aset result 13 (% sha1-H3-high 256)) + (aset result 14 (/ sha1-H3-low 256)) + (aset result 15 (% sha1-H3-low 256)) + (aset result 16 (/ sha1-H4-high 256)) + (aset result 17 (% sha1-H4-high 256)) + (aset result 18 (/ sha1-H4-low 256)) + (aset result 19 (% sha1-H4-low 256)) + result)) + ;; do not leave a copy of input string. + (fillarray block-high nil) + (fillarray block-low nil)))) + +(defun sha1-string-internal (string &optional binary) + (if binary + (sha1-binary string) + (encode-hex-string (sha1-binary string)))) + +(defun sha1-region-internal (beg end &optional binary) + (sha1-string-internal (buffer-substring-no-properties beg end) binary)) + +;;; +;;; application interface. +;;; + +(defun sha1-region (beg end &optional binary) + (if (and sha1-use-external + sha1-maximum-internal-length + (> (abs (- end beg)) sha1-maximum-internal-length)) + (sha1-region-external beg end binary) + (sha1-region-internal beg end binary))) + +(defun sha1-string (string &optional binary) + (if (and sha1-use-external + sha1-maximum-internal-length + (> (length string) sha1-maximum-internal-length)) + (sha1-string-external string binary) + (sha1-string-internal string binary))) + +;;;###autoload +(defun sha1 (object &optional beg end binary) + "Return the SHA1 (Secure Hash Algorithm) of an object. +OBJECT is either a string or a buffer. +Optional arguments BEG and END denote buffer positions for computing the +hash of a portion of OBJECT. +If BINARY is non-nil, return a string in binary form." + (if (stringp object) + (sha1-string object binary) + (save-excursion + (set-buffer object) + (sha1-region (or beg (point-min)) (or end (point-max)) binary)))) + +(provide 'sha1) + +;;; arch-tag: c0f9abd0-ffc1-4557-aac6-ece7f2d4c901 +;;; sha1.el ends here diff --git a/xemacs-packages/lisp/ecrypto/sha1.elc b/xemacs-packages/lisp/ecrypto/sha1.elc new file mode 100644 index 0000000000000000000000000000000000000000..efe10cf97eec4afa002405712d249ea67a95f333 GIT binary patch literal 6428 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 G&i?@~Tw=li literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/ChangeLog b/xemacs-packages/lisp/ediff/ChangeLog new file mode 100644 index 00000000..77f6dfdf --- /dev/null +++ b/xemacs-packages/lisp/ediff/ChangeLog @@ -0,0 +1,907 @@ +2006-02-22 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.62 released. + +2006-02-21 Michael Kifer + + * ediff-diff.el (ediff-setup-diff-regions, ediff-setup-diff-regions3): + fix the regular expressions. + +2006-02-20 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.61 released. + +2006-02-19 Michael Kifer + + * ediff-diff.el (ediff-ignore-case, ediff-ignore-case-option, + ediff-ignore-case-option3, ediff-actual-diff-options, + ediff-actual-diff3-options): new variables to control case sensitivity. + (ediff-make-diff2-buffer, ediff-setup-fine-diff-regions, + ediff-setup-diff-regions3): made aware of case-sensitivity. + (ediff-toggle-ignore-case): new function. + (ediff-extract-diffs, ediff-extract-diffs3): preserve point in buffers. + + * ediff-help.el (ediff-long-help-message-narrow2, + ediff-long-help-message-compare2, ediff-long-help-message-compare3, + ediff-long-help-message-word-mode): add ignore-case command. + (ediff-help-for-quick-help): add ignore-case command. + + * ediff-merg.el: move provide to the end. + + * ediff-ptch.el: move provide to the end. + + * ediff-wind.el: move provide to the end. + + * ediff-mult.el: move provide to the end. + (ediff-set-meta-overlay): enable follow-link. + + * ediff.el: move provide to the end. + Break recursive load cycle in eval-when-compile. + (ediff-patch-buffer): better heuristics. + + * ediff-util.el: move provide to the end. + Break recursive load cycle in eval-when-compile. + (ediff-setup-keymap): add binding for #c. Replaced some defsubsts with + defuns. + (ediff-submit-report): pass the values of ediff-diff3-program, + ediff-diff3-options. + +2005-12-05 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.60 released. + +2005-11-29 Michael Kifer + + * ediff-wind (ediff-setup-control-frame, ediff-make-wide-display): + preserve user position. + +2005-11-25 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.59 released. + +2005-11-25 Michael Kifer + + * ediff-wind (ediff-make-wide-display): Slight simplification. + + * ediff.el (ediff-date): Changed the date of last update. + +2005-11-16 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.58 released. + +2005-11-15 Michael Kifer + + * ediff-util (ediff-make-temp-file): use proper file-name-handler + operation + +2005-11-07 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.57 released. + +2005-11-04 Michael Kifer + + * ediff-merge.el (ediff-merge-region-is-non-clash): return t, if not + merging. + + * ediff-util.el (ediff-previous-difference): don't skip regions that + have merge clashes. + +2005-10-06 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.56 released. + +2005-10-05 Michael Kifer + + * ediff-merge.el (ediff-merge-region-is-non-clash): new defsubst. + (ediff-merge-region-is-non-clash-to-skip): previouslu called + ediff-merge-region-is-non-clash. + + * ediff-mult.el (ediff-append-custom-diff,ediff-meta-show-patch): use + insert-buffer-substring. + + * ediff-ptch.el (ediff-fixup-patch-map): use better heuristics for + selecting files to patch. Also bug fixes. + + * ediff-util.el (ediff-setup): bug fix. + (ediff-next-difference): Never skip clashes that differ in white space + only. + + * ediff-wind.el (ediff-setup-control-frame,ediff-destroy-control-frame): + check the menubar feature. + +2005-09-21 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.55 released. + +2005-09-20 Michael Kifer + + * ediff-ptch.el (ediff-file-name-sans-prefix): treat nil as an empty + string. + (ediff-fixup-patch-map): better heuristic for intuiting the file names + to patch. + (ediff-prompt-for-patch-file): more intuitive prompt. + + * ediff-util.el: use insert-buffer-substring. + + * ediff-vers.el (cvs-run-ediff-on-file-descriptor): bug fix. + +2005-07-19 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.54 released. + +2005-07-19 Michael Kifer + + * ediff.el (ediff-patch-buffer): changed the docstring. + + * ediff-diff.el: add defvar for longlines-mode. + +2005-07-10 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.53 released. + +2005-07-10 Michael Kifer + + * ediff-diff.el (ediff-extract-diffs,ediff-extract-diffs3): + Make it work with longlines mode + + * ediff-mult.el (ediff-meta-mode-hook): new variable. + + * ediff-ptch.el (ediff-file-name-sans-prefix): quote regexp. + + * ediff-init: got rid of -face in face names. + +2005-06-04 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.52 released. + +2005-06-03 Michael Kifer + + * ediff-diff.el (ediff-same-contents) Eliminate CL-type functions. + Replace string-to-int with string-to-number. + + * ediff-mult.el (ediff-intersect-directories) Make sure that ".." and + "." files are deleted from all file lists before comparison + +2005-02-19 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.51 released. + +2005-02-19 Michael Kifer + + * ediff.el (ediff-set-diff-overlays-in-one-buffer, + ediff-set-fine-overlays-in-one-buffer,ediff-goto-word) make sure + we use the syntax table of the correct buffer. + (ediff-same-file-contents,ediff-same-contents): enhancements thanks to + Felix Gatzemeier. + + * ediff-init.el (ediff-hide-face): checks for definedness of functions. + (ediff-file-remote-p): make synonymous with file-remote-p. + In all deffaces ediff-*-face-*, use min-colors. + + * ediff-mult.el (ediff-meta-mark-equal-files): make use of + ediff-recurse-to-subdirectories. + (ediff-mark-if-equal): check that the arguments are strings, use + ediff-same-contents (after to Felix Gatzemeier). + + * ediff.el (ediff-merge-on-startup): don't set buffer-modified-p to + nil. + +2004-02-20 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.50 released. + +2004-02-19 Michael Kifer + + * ediff-util.el (ediff-toggle-read-only): Remove extra format + string argument. + (ediff-toggle-regexp-match): Likewise. + Suggested by Andreas Schwab + * ediff-ptch.el (ediff-test-patch-utility): + * ediff-diff.el (ediff-test-utility): Don't use = or zerop to + test the return value of call-process, because it can be a string. + By Jesper Harder + +2004-02-19 Michael Kifer + + * ediff-util.el (ediff-compute-custom-diffs-maybe): Avoid creating + temporary file for buffer already visiting one. This change makes + output likely to be directly usable by patch program. + Suggested by Adrian Aichner + +2003-10-31 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.49 released. + +2003-10-13 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.48 released. + +2003-10-12 Michael Kifer + + * ediff-mult.el (ediff-filegroup-action): use + ediff-default-filtering-regexp. + + * ediff-util.el (ediff-recenter): don't call + ediff-restore-highlighting twice. + (ediff-select-difference): set current difference. + (ediff-unselect-and-select-difference): added comment. + + * ediff.el (ediff-directories,ediff-directory-revisions, + ediff-directories3,ediff-merge-directories, + ediff-merge-directories-with-ancestor,ediff-merge-directory-revisions, + ediff-merge-directory-revisions-with-ancestor): use + ediff-default-filtering-regexp. + +2003-05-19 Norbert Koch + + * Makefile (VERSION): XEmacs package 1.47 released. + +2003-05-18 Michael Kifer + + * ediff-mult.el (ediff-default-filtering-regexp): new variable. + + * ediff-util.el (ediff-maybe-save-and-delete-merge): change in a + message. + + * ediff.el (ediff-directories,ediff-directory-revisions, + ediff-directories3,ediff-merge-directories, + ediff-merge-directories-with-ancestor,ediff-merge-directory-revisions, + ediff-merge-directory-revisions-with-ancestor): make use of the new + ediff-default-filtering-regexp variable. + + * all files: eliminated trailing blanks in various lines. + +2003-03-09 Ben Wing + + * Makefile: + Delete explicit compile:: and binkit: rules. + Don't add custom-load.elc to the list of generated elc's. + Use STANDARD_DOCS instead of explicitly giving the targets + and dependencies. + +2003-01-26 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 1.46 released. + +2003-01-25 Michael Kifer + + * ediff.el (ediff-revision): better defaults. + + * ediff-vers.el (ediff-vc-latest-version): new function. + (ediff-vc-internal): use latest version instead of working version. + +2002-11-29 Ben Wing + + * .cvsignore: Remove files now handled automatically by CVS. + * Makefile: Use `compile' instead of hard-coded `all'. + +2002-12-06 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 1.45 released. + +2002-11-17 Michael Kifer + + * ediff-diff.el (ediff-setup-diff-regions): change regexp. + + * ediff-mult.el: comments. + + * ediff.el: comments. + +2002-10-29 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 1.44 released. + +2002-10-27 Michael Kifer + + * ediff-wind.el (ediff-control-frame-parameters): added scrollbar-height. + +2002-10-15 Ville Skyttä + + * Makefile (srckit): Remove. + +2002-10-14 Ville Skyttä + + * Makefile (MANUAL): Removed (unused). + +2002-10-14 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 1.43 released. + +2002-10-12 Michael Kifer + + * ediff-init.el (ediff-frame-char-height): use frame-selected-window. + + * ediff-util.el (ediff-file-checked-in-p): changed progn with and + + * ediff-wind.el (ediff-skip-unsuitable-frames): distinguish selected + frame from frame of selected window + (ediff-frame-has-dedicated-windows): don't select any frames to avoid + changing selected windows + (ediff-setup-control-frame): make sure auto-rase is properly set for + the control frame + +2002-09-25 Rendhalver [Peter Brown] + + * Makefile (VERSION): XEmacs package 1.42 released. + +2002-09-23 Michael Kifer + + * ediff-init.el (ediff-get-next-window): bug fix. + + * ediff-hook.el (ediff-cond-compile-for-xemacs-or-emacs): Put the + definition straight into loaddefs.el as well as executing it here + (by RMS) + +2002-09-18 Michael Kifer + + * ediff-hooks.el: Put back the autoloads (for compatibility with XEmacs). + + * ediff-init.el: Use defalias instead of fset. + + * ediff-util.el: Use defalias instead of fset. + + * ediff-ptch.el (ediff-test-patch-utility): catch errors + + * ediff-wind.el (ediff-window-setup-function): better choices + + * ediff-backup.el (ediff-backup): new function + + * ediff.texi: typo + +2002-07-16 Adrian Aichner + + * .cvsignore: Add generated .info* and .html files. + +2002-04-30 Steve Youngs + + * Makefile (VERSION): XEmacs package 1.41 released. + +2002-04-25 Michael Kifer + + * ediff-hooks.el: Put back the autoloads. + +2002-04-24 Steve Youngs + + * Makefile (VERSION): XEmacs package 1.40 released. + +2002-04-16 Michael Kifer + + * ediff-init.el: better defaults for all faces -- thanks to Eli + Zaretskii. + + * ediff-util.el (ediff-cleanup-mess): delete ctl window on exit + when the window is not in its own frame. + (ediff-clone-buffer-for-region-comparison): more robust window + arrangement while prompting for regions to compare. + (ediff-make-cloned-buffer): use generate-new-buffer-name. + (ediff-inferior-compare-regions): deleted unused vars + ctl-buf and quit-now. + +2002-03-25 Steve Youngs + + * Makefile (VERSION): 1.39 released. + +2002-03-20 Michael Kifer + + * ediff-diff.el (ediff-install-fine-diff-if-necessary): take + the current highlighting style into account. + (ediff-forward-word-function,ediff-whitespace,ediff-word-1, + ediff-word-2,ediff-word-3,ediff-word-4): make them buffer local. + + * ediff-init.el (ediff-patch-job): new macro. + + * ediff-mult.el (ediff-make-new-meta-list-header): new API function. + (ediff-intersect-directories): use ediff-make-new-meta-list-header. + + * ediff-ptch.el (ediff-map-patch-buffer): use + ediff-make-new-meta-list-header. + (ediff-fixup-patch-map): use the meta-list API from ediff-mult.el. + + * ediff-util.el (ediff-toggle-hilit): fix toggling of highliting. + (ediff-select-difference): take highlighting style into account. + (ediff-clone-buffer-for-region-comparison): new function. + (ediff-inferior-compare-regions): added comparison of current diff + regions. + + * ediff.el (ediff-clone-buffer-for-region-comparison, + ediff-clone-buffer-for-window-comparison): moved to ediff-util.el. + +2002-03-05 Michael Kifer + + * ediff-init.el: comments. + + * ediff-hook.el: Got rid of autoloads. Not needed, since the hook + is loaded. + + * ediff-mult.el (ediff-intersect-directories, + ediff-prepare-meta-buffer,ediff-get-directory-files-under-revision): + cleanup. + (ediff-draw-dir-diffs): now supports the "C" command in directory + difference buffer. + (ediff-dir-diff-copy-file): new function that implements copying + of files from one Ediff dir to another + (ediff-bury-dir-diffs-buffer): kills the buffer instead. + (ediff-append-custom-diff): better error msgs. + + * ediff-util.el (ediff-compute-custom-diffs-maybe): buglet fix. + (ediff-inferior-compare-regions): Use + ediff-clone-buffer-for-region-comparison. Better and simpler interface. + + * ediff.el (ediff-directories-internal): Cleanup. + (ediff-clone-buffer-for-region-comparison): Better interface. + +2002-02-09 Michael Kifer + + * ediff-init.el (ediff-has-gutter-support): Steven Turnbull's patch. + + * ediff-wind.el (ediff-setup-control-frame): Use + ediff-has-gutter-support. + +2002-02-09 Michael Kifer + + * ediff-util.el (ediff-dispose-of-variant-according-to-user): + check if buff is alive. + + * ediff.el: typo in comment. + +2002-01-08 Michael Kifer + + * ediff-hook.el: added autoload cookie + +2002-01-07 Michael Kifer + + * ediff-help.el: use ediff-cond-compile-for-xemacs-or-emacs. + + * ediff-hook.el: use ediff-cond-compile-for-xemacs-or-emacs. + + * ediff-init.el (ediff-cond-compile-for-xemacs-or-emacs): new + macro designed to be used in many places where ediff-emacs-p or + ediff-xemacs-p was previously used. Reduces the number of + warnings. + Use ediff-cond-compile-for-xemacs-or-emacs in many places in lieue + of ediff-xemacs-p. + (ediff-make-current-diff-overlay, ediff-highlight-diff-in-one-buffer, + ediff-convert-fine-diffs-to-overlays, ediff-empty-diff-region-p, + ediff-whitespace-diff-region-p, ediff-get-region-contents): + moved to ediff-util.el. + (ediff-event-key): moved here. + + * ediff-merge.el: got rid of unreferenced variables. + + * ediff-mult.el: use ediff-cond-compile-for-xemacs-or-emacs. + + * ediff-util.el: use ediff-cond-compile-for-xemacs-or-emacs. + (ediff-cleanup-mess): improved the way windows are set up after + quitting ediff. + (ediff-janitor): use ediff-dispose-of-variant-according-to-user. + (ediff-dispose-of-variant-according-to-user): new function + designed to be smarter and also understands indirect buffers. + (ediff-highlight-diff-in-one-buffer, + ediff-unhighlight-diff-in-one-buffer, + ediff-unhighlight-diffs-totally-in-one-buffer, + ediff-highlight-diff, ediff-highlight-diff, + ediff-unhighlight-diff, ediff-unhighlight-diffs-totally, + ediff-empty-diff-region-p, ediff-whitespace-diff-region-p, + ediff-get-region-contents, ediff-make-current-diff-overlay): + moved here. + (ediff-format-bindings-of): new function by Hannu Koivisto + . + (ediff-setup): make sure the merge buffer is always widened and + modifiable. + (ediff-write-merge-buffer-and-maybe-kill): refuse to write the + result of a merge into a file visited by another buffer. + (ediff-arrange-autosave-in-merge-jobs): check if the merge file + is visited by another buffer and ask to save/delete that buffer. + (ediff-verify-file-merge-buffer): new function to do the above. + + * ediff-vers.el: load ediff-init.el at compile time. + + * ediff-wind.el: use ediff-cond-compile-for-xemacs-or-emacs. + + * ediff.el (ediff-windows, ediff-regions-wordwise, + ediff-regions-linewise): use indirect buffers to improve + robustness and make it possible to compare regions of the same + buffer (even overlapping regions). + (ediff-clone-buffer-for-region-comparison, + ediff-clone-buffer-for-window-comparison): new functions. + (ediff-files-internal): refuse to compare identical files. + (ediff-regions-internal): get rid of the warning about comparing + regions of the same buffer. + + * ediff-diff.el (ediff-convert-fine-diffs-to-overlays): moved here. + Plus the following fixes courtesy of Dave Love: + Doc fixes. + (ediff-word-1): Use word class and move - to the + front per regexp documentation. + (ediff-wordify): Bind forward-word-function outside loop. + (ediff-copy-to-buffer): Use insert-buffer-substring rather than + consing buffer contents. + (ediff-goto-word): Move syntax table setting outside loop. + +2002-01-07 Adrian Aichner + + * Makefile (HTML_FILES): New. + * Makefile (HTML_DEP): New. + +2001-12-30 Steve Youngs + + * package-info.in (provides): Update to include all provides. + +2001-12-24 Michael Kifer + + * ediff-mult.el (ediff-meta-mark-equal-files): Added optional + action argument. + + * ediff-init.el: Fixed some doc strings. + + * ediff-util.el (ediff-after-quit-hook-internal): New variable. + Got rid of make-local-hook. + + * ediff-wind.el (ediff-setup-control-frame): Got rid of + make-local-hook. + +2001-09-27 Michael Kifer + + * ediff-mult.el (ediff-get-meta-info): Installed Gerd's changes. + Added comments. + +2001-09-09 Michael Kifer + + * ediff-init.el (ediff-highest-priority): bug fix. + + * ediff-mult.el (ediff-get-meta-info): replace and with or. + +2001-07-21 Michael Kifer + + * ediff-util.el + (ediff-file-checked-out-p,ediff-file-checked-in-p): check if + vc-state is available. + (ediff-make-temp-file): use ediff-coding-system-for-write. + + * ediff-init.el (ediff-coding-system-for-read): from ediff-diff.el + (ediff-coding-system-for-write): new variable. + (ediff-highest-priority): fixed the bug having to do with disappearing + overlays. + (ediff-file-remote-p): use file-remote-p, if available. + (ediff-listable-file): new function. + (ediff-file-attributes): use ediff-listable-file. + + * ediff-mult.el (ediff-meta-insert-file-info1): use + ediff-listable-file. + + * ediff-ptch.el (ediff-prompt-for-patch-file): use + ediff-coding-system-for-read. + (ediff-patch-file-internal): use ediff-coding-system-for-write. + + * ediff-diff.el (ediff-coding-system-for-read): moved to ediff-init.el. + (ediff-match-diff3-line,ediff-get-diff3-group): improved pattern. + + * ediff.texi: added clarifications, acknowledgements. + +2001-04-08 Steve Youngs + + * Makefile (REQUIRES): Add prog-modes because diff-mode.el + has moved there. + +2001-03-17 Michael Kifer + + * ediff-util.el: Copyright years. + (ediff-choose-syntax-table): New function. + (ediff-setup): Use ediff-choose-syntax-table. + + * ediff-init.el (ediff-with-syntax-table): New macro, uses + with-syntax-table. + + * ediff.el: Date of last update, copyright years. + + * ediff-wind (ediff-setup-control-frame): Nill->nil. + +2001-02-24 Michael Kifer + + * ediff.texi: Fixed some typos + +2001-02-12 Michael Kifer + + * ediff-diff.el (ediff-make-diff2-buffer): Removed bogus checks + for remote files. + (ediff-coding-system-for-read): replaced the no-conversion default + with raw-text. + + * ediff-init.el: Removed :version from defcustom vars. + + * ediff-util.el (ediff-compute-custom-diffs-maybe): Better + handling of the diff mode + + * ediff.texi: Added ediff-coding-system-for-read. + +2001-01-19 Michael Kifer + + * ediff.el (ediff-patch-file): use better defaults. + + * ediff-vers.el: fix for 8+3 DOS file systems + + * ediff.texi: add credits. + +2001-01-19 Colin Walters + + * ediff-util.el (ediff-compare-custom-diffs-maybe): put diff in + diff mode, if available. + +2001-01-19 Vin Shelton + + * ediff-hook.el (ediff-xemacs-init-menus): fixed add-menu-button + +2001-01-19 Steve Youngs + + * ediff-init.el (subst-char-in-string): Define and use it, unless + it's already defined. + +2001-01-17 Stephen J. Turnbull + + * Makefile: Add edebug to REQUIRES (for def-edebug-spec). + +2000-12-25 Michael Kifer + + * ediff-init.el (ediff-quit-hook,ediff-suspend-hook): changed + initialization; use add-hook. + (ediff-file-remote-p): use file-local-copy. + + * ediff-ptch.el (ediff-prompt-for-patch-buffer): improved defaults. + + * ediff.el (ediff-patch-buffer): bug fix. + (ediff-revision): allow selection of the file at the prompt. + +2000-11-24 Michael Kifer + + * ediff-diff.el: Moved variables around to have it compile under NT. + + * ediff-help.el (ediff-use-long-help-message): made it customizable. + + * ediff-init.el (ediff-abbrev-jobname): use capitalize. + + * ediff-wind.el (ediff-skip-unsuitable-frames): deleted the + redundant skip-small-frames test. + +2000-10-29 Michael Kifer + + * ediff-wind.el (ediff-setup-control-frame): enclose + face-attribute in condition-case to avoid errors in older emacsen. + +2000-10-29 Michael Kifer + + * ediff-init.el (ediff-before-setup-hook): new hook. + Several typos fixed in various docstrings. + * ediff-merg.el (ediff-show-clashes-only): docstring typo fixed. + * ediff-nult.el (ediff-before-session-group-setup-hooks): new + hook. + (ediff-show-meta-buffer): run ediff-before-session-group-setup-hooks. + * ediff-util.el (ediff-setup): run ediff-before-setup-hook. + (ediff-other-buffer): use selected buffers if in Buffer-menu buffer. + (ediff-get-selected-buffers): new function. + * ediff-vers.el (ediff-vc-internal,ediff-rcs-internal, + ediff-vc-merge-internal,ediff-rcs-merge-internal): use + save-window-excursion. + * ediff-wind.el (ediff-skip-unsuitable-frames): more robust + termination check in while loop. + * ediff.el (ediff-get-default-file-name): better defaults when in + dired buffer. + (ediff-files,ediff-merge-files,ediff-files3, + ediff-merge-files-with-ancestor): use ediff-get-default-file-name. + +2000-07-05 Michael Kifer + + * ediff-diff.el (ediff-wordify): use syntax table. + * ediff-init.el (ediff-has-face-support-p): use + ediff-color-display-p. + (ediff-color-display-p): use display-color-p, changed to defun + from defsubst. + Got rid of special cases for NeXT and OS/2. + * ediff-wind.el (ediff-setup-control-frame): set proper modeline + face. + +2000-06-05 Michael Kifer + + * ediff-init.el (ediff-has-face-support-p): make it paint faces on + tty's. + * ediff-diff.el (ediff-exec-process): use --binary for fine + differences whenever apropriate. + +2000-05-25 Michael Kifer + + * ediff-diff.el (ediff-exec-process): delete --binary option from + non-buffer ediff jobs. + +2000-05-24 Michael Kifer + + * ediff-diff.el (ediff-forward-word): take syntactic word class into + account. + (ediff-test-utility,ediff-diff-mandatory-option, + ediff-reset-diff-options): utilities for proper initialization of + ediff-diff-options and ediff-diff3-options on Windows. + + * ediff-init.el (ediff-merge-filename-prefix): new customizable + variable. + + * ediff-mult.el (ediff-filegroup-action): use + ediff-merge-filename-prefix. + +2000-2-28 Michael Kifer + * ediff-wind.el: minor comment changes. + * ediff.el: copyright notice date fix. + +1999-12-15 Gunnar Evermann + + * ediff-help.el (ediff-customize): Add autoload cookie. + +1999-11-24 Michael Kifer + + * ediff*el: replaced old-style backquotes. + + * ediff-merge + (ediff-looks-like-combined-merge,ediff-get-combined-region): + changed to support the new format for ediff-combination-pattern. + + * ediff-diff (ediff-set-fine-overlays-in-one-buffer): + changed to support the new format for ediff-combination-pattern. + + * ediff.texi: Describe the new format for + ediff-combination-pattern. + +1999-11-01 Michael Kifer + + * ediff-diff.el (ediff-cmp-options): new var. + (ediff-same-file-contents): use ediff-cmp-options. + + * ediff-ptch.el (ediff-prompt-for-patch-buffer, + ediff-get-patch-buffer): use current buffer if it appears to be a + patch. + + * ediff-util.el (ediff-file-checked-in-p): don't consider CVS + files checked in. + (ediff-make-temp-file,ediff-make-empty-tmp-file): Make sure you + are writing to a newly created empty file. + + * ediff.texi: minor improvements. + +1999-08-18 Michael Kifer + + * ediff-init.el (ediff-temp-file-prefix): better initialization + + * eviff-vers.el (ediff-vc-merge-internal): small buglet fix + + * ediff.el: comment change + +1999-05-27 SL Baur + + * Makefile: bump version number. + +1999-05-16 Michael Kifer + + * ediff.el, ediff-util.el: Enable ediff-merge-directories-* to be + called with a parameter that specifies the directory where the + merged files are to be saved. + +1999-04-06 Andreas Jaeger + + * ediff.texi: Add comma to satisfy texinfo 3.12f+'s grammar + checker. + +1999-03-03 Michael Kifer + + * ediff-mult.el (ediff-get-directory-files-under-revision): Use + absolute file names. + +1999-03-03 Adrian Aichner + + * ediff-init.el (stipple-pixmap): Locate "stipple" library in + x-bitmap-file-path if bound, else try to locate it in + mswindows-bitmap-file-path, if bound. + +1999-02-16 Michael Kifer + + * ediff-help.el (ediff-customize): new command. + + * ediff-hooks.el: added menu item for customizing ediff. + +1999-02-06 SL Baur + + * ediff-init.el (stipple-pixmap): Move x bitmap dependency to + runtime. + +1999-01-18 Michael Kifer + + * ediff-patch.el: (ediff-patch-buffer-internal): changed message. + +1998-12-09 SL Baur + + * ediff-tbar.el (ediff-toolbar-icon-directory): Don't assume there + is always toolbar support. + +1998-10-8 Michael Kifer + + * ediff-util.el (ediff-cleanup-mess): fixed the case of dead windows. + make sure you are in a good frame before deleting other + windows. + + * ediff-mult.el (ediff-show-session-group-hook): new default. + + * ediff-vers.el (ediff-pcl-cvs-view-revision): + first cd to the file directory. reportedly works + better with remote files. + + * ediff-vers.el (ediff-pcl-cvs-internal, ediff-pcl-cvs-merge-internal): + use file-name-nondirectory when passing files to CVS. + +1998-07-20 Michael Kifer + + * ediff-help.el (ediff-long-help-message-merge): default changed. + + * ediff-util.el (ediff-status-info): updated. + (ediff-toggle-skip-changed-regions): new function. + (ediff-next-difference, ediff-previous-difference): + now skips white space correctly in the merge mode. + (ediff-write-merge-buffer-and-maybe-kill, + ediff-maybe-save-and-delete-merge): changed to give more options to + the user. + (ediff-other-buffer): no longer skips mail buffers. + + * ediff-merg.el (ediff-skip-merge-regions-that-differ-from-default): + new variable. + (ediff-skip-merge-region-if-changed-from-default-p, + ediff-merge-changed-from-default-p): new functions. + + * ediff-wind.el (ediff-control-frame-parameters): + improved, to reduce distraction. + (ediff-skip-unsuitable-frames): make it skip small windows. + + * ediff-diff.el, ediff-init.el: Improved comments. + + * ediff-mult.el (ediff-hide-marked-sessions): + make it redraw the meta buffer. + (ediff-collect-custom-diffs): make the diff buffer read-only, not + modified. + (ediff-mark-for-hiding, ediff-mark-for-operation): renamed to *-at-pos. + (ediff-mark-session-for-hiding, ediff-mark-session-for-operation, + ediff-unmark-all-for-operation, ediff-unmark-all-for-hiding): new + functions. + (ediff-setup-meta-map): changed bindings. + + * ediff.el, ediff-init.el, ediff-ptch.el, ediff-help.el, + ediff-diff.el, ediff-tbar.el, ediff-wind.el, ediff-mult.el: Removed + function quotes around lambdas. + + * ediff.texi: add section about $*. + + +1998-04-27 SL Baur + + * dumped-lisp.el: removed. + +1998-02-25 SL Baur + + * ediff-tbar.el (ediff-toolbar-icon-directory): New variable. + (ediff-toolbar-next-icon): Use it. + (ediff-toolbar-previous-icon): Ditto. + (ediff-toolbar-A-icon): Ditto. + (ediff-toolbar-B-icon): Ditto. + (ediff-toolbar-toggle-split-icon): Ditto. + (ediff-toolbar-save-icon): Ditto. + (ediff-toolbar-quit-icon): Ditto. + (ediff-toolbar-help-icon): Ditto. + (ediff-toolbar-refresh-icon): Ditto. + (ediff-toolbar-refine-icon): Ditto. + + * ediff.texi: Add direntry section for automated installation. + +1998-01-24 SL Baur + + * Makefile (VERSION): Update to package standard 1.0. + * package-info.in: Ditto. + +1998-01-03 SL Baur + + * Makefile: Update to newer package interface. + +1997-12-25 SL Baur + + * Makefile: Created. diff --git a/xemacs-packages/lisp/ediff/README b/xemacs-packages/lisp/ediff/README new file mode 100644 index 00000000..dd5a58fd --- /dev/null +++ b/xemacs-packages/lisp/ediff/README @@ -0,0 +1,70 @@ +**** EDIFF -- a comprehensive interface to diff for Emacs and XEmacs + +This directory: + +README -- This file +Makefile -- Automated installation file +ediff.texi -- Manual in Texinfo format +ediff, ediff-? -- The Info files +ediff.dvi -- Manual in DVI format + +ediff.el -- Ediff Emacs Lisp code +ediff-init.el -- Ediff Emacs Lisp code +ediff-help.el -- Ediff Emacs Lisp code +ediff-wind.el -- Ediff Emacs Lisp code +ediff-util.el -- Ediff Emacs Lisp code +ediff-diff.el -- Ediff Emacs Lisp code +ediff-merg.el -- Ediff Emacs Lisp code +ediff-mult.el -- Ediff Emacs Lisp code +ediff-vers.el -- Ediff Emacs Lisp code +ediff-ptch.el -- Ediff Emacs Lisp code +ediff-tbar.el -- Ediff Emacs Lisp code -- for XEmacs only +ediff-hook.el -- Ediff Emacs Lisp code +toolbar/ -- Ediff toolbar icons -- for XEmacs only + + +To install Ediff do: + + uncompress ediff.tar.Z + tar xf ediff.tar + + +Then do the following: + +1. To compile Lisp: + + make (or 'make all') + +2. You can also type + + make install + + to do what "make all" does plus it will copy the files ediff*.elc + into a suitable Lisp directory. + + To make this happen, you will most likely have to change the PREFIX + variable in Makefile and, possibly, one or more of these variables: + + DATADIR, LISPDIR, INFODIR, ETCDIR, and VERSION + + if they don't point to the right directories in your installation. + You also need to have a write permission for all directories + mentioned in LISPDIR, INFODIR, and ETCDIR. + +3. XEmacs users must invoke `make' with the parameter EMACS=xemacs. + Even better: edit Makefile directly. + +4. Under XEmacs, copy the icons in the `toolbar' directory into + the-directory-where-xemacs-installed/etc/toolbar/ + +Normally, all Ediff menus and autoloads are already defined in Emacs, so you +don't need to define anything in your .emacs to run Ediff. +However, if it was announced that this distribution of Ediff contains +new features, you may need to put + +(require 'ediff-hook) + +in your .emacs to take advantage of these new features. This doesn't load +Ediff, but readies Emacs for the things to come. When this version of +Ediff gets installed in the standard Emacs distribution, you can remove +the above require-statement (but leaving it in does no harm). diff --git a/xemacs-packages/lisp/ediff/_pkg.el b/xemacs-packages/lisp/ediff/_pkg.el new file mode 100644 index 00000000..3c55d88b --- /dev/null +++ b/xemacs-packages/lisp/ediff/_pkg.el @@ -0,0 +1,5 @@ +;;;###autoload +(package-provide 'ediff + :version 1.62 + :author-version "2.75" + :type 'regular) diff --git a/xemacs-packages/lisp/ediff/auto-autoloads.el b/xemacs-packages/lisp/ediff/auto-autoloads.el new file mode 100644 index 00000000..09bc5521 --- /dev/null +++ b/xemacs-packages/lisp/ediff/auto-autoloads.el @@ -0,0 +1,230 @@ +;;; DO NOT MODIFY THIS FILE +(if (featurep 'ediff-autoloads) (error "Already loaded")) + +;;;### (autoloads nil "_pkg" "ediff/_pkg.el") + +(package-provide 'ediff :version 1.62 :author-version "2.75" :type 'regular) + +;;;*** + +;;;### (autoloads (ediff-customize) "ediff-help" "ediff/ediff-help.el") + +(autoload 'ediff-customize "ediff-help" nil t nil) + +;;;*** + +;;;### (autoloads nil "ediff-hook" "ediff/ediff-hook.el") + +(defvar ediff-window-setup-function) +(defmacro ediff-cond-compile-for-xemacs-or-emacs (xemacs-form emacs-form) (if (string-match "XEmacs" emacs-version) xemacs-form emacs-form)) + +(ediff-cond-compile-for-xemacs-or-emacs (defun ediff-xemacs-init-menus nil (if (featurep 'menubar) (progn (add-submenu '("Tools") ediff-menu "OO-Browser...") (add-submenu '("Tools") ediff-merge-menu "OO-Browser...") (add-submenu '("Tools") epatch-menu "OO-Browser...") (add-submenu '("Tools") ediff-misc-menu "OO-Browser...") (add-menu-button '("Tools") "-------" "OO-Browser...")))) nil) + +(ediff-cond-compile-for-xemacs-or-emacs (progn (defvar ediff-menu '("Compare" ["Two Files..." ediff-files t] ["Two Buffers..." ediff-buffers t] ["Three Files..." ediff-files3 t] ["Three Buffers..." ediff-buffers3 t] "---" ["Two Directories..." ediff-directories t] ["Three Directories..." ediff-directories3 t] "---" ["File with Revision..." ediff-revision t] ["Directory Revisions..." ediff-directory-revisions t] "---" ["Windows Word-by-word..." ediff-windows-wordwise t] ["Windows Line-by-line..." ediff-windows-linewise t] "---" ["Regions Word-by-word..." ediff-regions-wordwise t] ["Regions Line-by-line..." ediff-regions-linewise t])) (defvar ediff-merge-menu '("Merge" ["Files..." ediff-merge-files t] ["Files with Ancestor..." ediff-merge-files-with-ancestor t] ["Buffers..." ediff-merge-buffers t] ["Buffers with Ancestor..." ediff-merge-buffers-with-ancestor t] "---" ["Directories..." ediff-merge-directories t] ["Directories with Ancestor..." ediff-merge-directories-with-ancestor t] "---" ["Revisions..." ediff-merge-revisions t] ["Revisions with Ancestor..." ediff-merge-revisions-with-ancestor t] ["Directory Revisions..." ediff-merge-directory-revisions t] ["Directory Revisions with Ancestor..." ediff-merge-directory-revisions-with-ancestor t])) (defvar epatch-menu '("Apply Patch" ["To a file..." ediff-patch-file t] ["To a buffer..." ediff-patch-buffer t])) (defvar ediff-misc-menu '("Ediff Miscellanea" ["Ediff Manual" ediff-documentation t] ["Customize Ediff" ediff-customize t] ["List Ediff Sessions" ediff-show-registry t] ["Use separate frame for Ediff control buffer" ediff-toggle-multiframe :style toggle :selected (if (and (featurep 'ediff-util) (boundp 'ediff-window-setup-function)) (eq ediff-window-setup-function 'ediff-setup-windows-multiframe))] ["Use a toolbar with Ediff control buffer" ediff-toggle-use-toolbar :style toggle :selected (if (featurep 'ediff-tbar) (ediff-use-toolbar-p))])) (if (and (featurep 'menubar) (not (featurep 'infodock)) (not (featurep 'ediff-hook))) (ediff-xemacs-init-menus))) (if (featurep 'menu-bar) (progn (defvar menu-bar-ediff-misc-menu (make-sparse-keymap "Ediff Miscellanea")) (fset 'menu-bar-ediff-misc-menu (symbol-value 'menu-bar-ediff-misc-menu)) (defvar menu-bar-epatch-menu (make-sparse-keymap "Apply Patch")) (fset 'menu-bar-epatch-menu (symbol-value 'menu-bar-epatch-menu)) (defvar menu-bar-ediff-merge-menu (make-sparse-keymap "Merge")) (fset 'menu-bar-ediff-merge-menu (symbol-value 'menu-bar-ediff-merge-menu)) (defvar menu-bar-ediff-menu (make-sparse-keymap "Compare")) (fset 'menu-bar-ediff-menu (symbol-value 'menu-bar-ediff-menu)) (define-key menu-bar-ediff-menu [window] '("This Window and Next Window" . compare-windows)) (define-key menu-bar-ediff-menu [ediff-windows-linewise] '("Windows Line-by-line..." . ediff-windows-linewise)) (define-key menu-bar-ediff-menu [ediff-windows-wordwise] '("Windows Word-by-word..." . ediff-windows-wordwise)) (define-key menu-bar-ediff-menu [separator-ediff-windows] '("--")) (define-key menu-bar-ediff-menu [ediff-regions-linewise] '("Regions Line-by-line..." . ediff-regions-linewise)) (define-key menu-bar-ediff-menu [ediff-regions-wordwise] '("Regions Word-by-word..." . ediff-regions-wordwise)) (define-key menu-bar-ediff-menu [separator-ediff-regions] '("--")) (define-key menu-bar-ediff-menu [ediff-dir-revision] '("Directory Revisions..." . ediff-directory-revisions)) (define-key menu-bar-ediff-menu [ediff-revision] '("File with Revision..." . ediff-revision)) (define-key menu-bar-ediff-menu [separator-ediff-directories] '("--")) (define-key menu-bar-ediff-menu [ediff-directories3] '("Three Directories..." . ediff-directories3)) (define-key menu-bar-ediff-menu [ediff-directories] '("Two Directories..." . ediff-directories)) (define-key menu-bar-ediff-menu [separator-ediff-files] '("--")) (define-key menu-bar-ediff-menu [ediff-buffers3] '("Three Buffers..." . ediff-buffers3)) (define-key menu-bar-ediff-menu [ediff-files3] '("Three Files..." . ediff-files3)) (define-key menu-bar-ediff-menu [ediff-buffers] '("Two Buffers..." . ediff-buffers)) (define-key menu-bar-ediff-menu [ediff-files] '("Two Files..." . ediff-files)) (define-key menu-bar-ediff-merge-menu [ediff-merge-dir-revisions-with-ancestor] '("Directory Revisions with Ancestor..." . ediff-merge-directory-revisions-with-ancestor)) (define-key menu-bar-ediff-merge-menu [ediff-merge-dir-revisions] '("Directory Revisions..." . ediff-merge-directory-revisions)) (define-key menu-bar-ediff-merge-menu [ediff-merge-revisions-with-ancestor] '("Revisions with Ancestor..." . ediff-merge-revisions-with-ancestor)) (define-key menu-bar-ediff-merge-menu [ediff-merge-revisions] '("Revisions..." . ediff-merge-revisions)) (define-key menu-bar-ediff-merge-menu [separator-ediff-merge] '("--")) (define-key menu-bar-ediff-merge-menu [ediff-merge-directories-with-ancestor] '("Directories with Ancestor..." . ediff-merge-directories-with-ancestor)) (define-key menu-bar-ediff-merge-menu [ediff-merge-directories] '("Directories..." . ediff-merge-directories)) (define-key menu-bar-ediff-merge-menu [separator-ediff-merge-dirs] '("--")) (define-key menu-bar-ediff-merge-menu [ediff-merge-buffers-with-ancestor] '("Buffers with Ancestor..." . ediff-merge-buffers-with-ancestor)) (define-key menu-bar-ediff-merge-menu [ediff-merge-buffers] '("Buffers..." . ediff-merge-buffers)) (define-key menu-bar-ediff-merge-menu [ediff-merge-files-with-ancestor] '("Files with Ancestor..." . ediff-merge-files-with-ancestor)) (define-key menu-bar-ediff-merge-menu [ediff-merge-files] '("Files..." . ediff-merge-files)) (define-key menu-bar-epatch-menu [ediff-patch-buffer] '("To a Buffer..." . ediff-patch-buffer)) (define-key menu-bar-epatch-menu [ediff-patch-file] '("To a File..." . ediff-patch-file)) (define-key menu-bar-ediff-misc-menu [emultiframe] '("Toggle use of separate control buffer frame" . ediff-toggle-multiframe)) (define-key menu-bar-ediff-misc-menu [eregistry] '("List Ediff Sessions" . ediff-show-registry)) (define-key menu-bar-ediff-misc-menu [ediff-cust] '("Customize Ediff" . ediff-customize)) (define-key menu-bar-ediff-misc-menu [ediff-doc] '("Ediff Manual" . ediff-documentation))))) + +;;;*** + +;;;### (autoloads (ediff-show-registry) "ediff-mult" "ediff/ediff-mult.el") + +(autoload 'ediff-show-registry "ediff-mult" "\ +Display Ediff's registry." t nil) + +(defalias 'eregistry 'ediff-show-registry) + +;;;*** + +;;;### (autoloads (ediff-toggle-use-toolbar ediff-toggle-multiframe) "ediff-util" "ediff/ediff-util.el") + +(autoload 'ediff-toggle-multiframe "ediff-util" "\ +Switch from multiframe display to single-frame display and back. +To change the default, set the variable `ediff-window-setup-function', +which see." t nil) + +(autoload 'ediff-toggle-use-toolbar "ediff-util" "\ +Enable or disable Ediff toolbar. +Works only in versions of Emacs that support toolbars. +To change the default, set the variable `ediff-use-toolbar-p', which see." t nil) + +;;;*** + +;;;### (autoloads (ediff-documentation ediff-version ediff-revision ediff-patch-buffer ediff-patch-file run-ediff-from-cvs-buffer ediff-merge-revisions-with-ancestor ediff-merge-revisions ediff-merge-buffers-with-ancestor ediff-merge-buffers ediff-merge-files-with-ancestor ediff-merge-files ediff-regions-linewise ediff-regions-wordwise ediff-windows-linewise ediff-windows-wordwise ediff-merge-directory-revisions-with-ancestor ediff-merge-directory-revisions ediff-merge-directories-with-ancestor ediff-merge-directories ediff-directories3 ediff-directory-revisions ediff-directories ediff-buffers3 ediff-buffers ediff-backup ediff-files3 ediff-files) "ediff" "ediff/ediff.el") + +(autoload 'ediff-files "ediff" "\ +Run Ediff on a pair of files, FILE-A and FILE-B." t nil) + +(autoload 'ediff-files3 "ediff" "\ +Run Ediff on three files, FILE-A, FILE-B, and FILE-C." t nil) + +(defalias 'ediff3 'ediff-files3) + +(defalias 'ediff 'ediff-files) + +(autoload 'ediff-backup "ediff" "\ +Run Ediff on FILE and its backup file. +Uses the latest backup, if there are several numerical backups. +If this file is a backup, `ediff' it with its original." t nil) + +(autoload 'ediff-buffers "ediff" "\ +Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B." t nil) + +(defalias 'ebuffers 'ediff-buffers) + +(autoload 'ediff-buffers3 "ediff" "\ +Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C." t nil) + +(defalias 'ebuffers3 'ediff-buffers3) + +(autoload 'ediff-directories "ediff" "\ +Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have +the same name in both. The third argument, REGEXP, is nil or a regular +expression; only file names that match the regexp are considered." t nil) + +(defalias 'edirs 'ediff-directories) + +(autoload 'ediff-directory-revisions "ediff" "\ +Run Ediff on a directory, DIR1, comparing its files with their revisions. +The second argument, REGEXP, is a regular expression that filters the file +names. Only the files that are under revision control are taken into account." t nil) + +(defalias 'edir-revisions 'ediff-directory-revisions) + +(autoload 'ediff-directories3 "ediff" "\ +Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that +have the same name in all three. The last argument, REGEXP, is nil or a +regular expression; only file names that match the regexp are considered." t nil) + +(defalias 'edirs3 'ediff-directories3) + +(autoload 'ediff-merge-directories "ediff" "\ +Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have +the same name in both. The third argument, REGEXP, is nil or a regular +expression; only file names that match the regexp are considered." t nil) + +(defalias 'edirs-merge 'ediff-merge-directories) + +(autoload 'ediff-merge-directories-with-ancestor "ediff" "\ +Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors. +Ediff merges files that have identical names in DIR1, DIR2. If a pair of files +in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge +without ancestor. The fourth argument, REGEXP, is nil or a regular expression; +only file names that match the regexp are considered." t nil) + +(autoload 'ediff-merge-directory-revisions "ediff" "\ +Run Ediff on a directory, DIR1, merging its files with their revisions. +The second argument, REGEXP, is a regular expression that filters the file +names. Only the files that are under revision control are taken into account." t nil) + +(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions) + +(autoload 'ediff-merge-directory-revisions-with-ancestor "ediff" "\ +Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors. +The second argument, REGEXP, is a regular expression that filters the file +names. Only the files that are under revision control are taken into account." t nil) + +(defalias 'edir-merge-revisions-with-ancestor 'ediff-merge-directory-revisions-with-ancestor) + +(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor) + +(autoload 'ediff-windows-wordwise "ediff" "\ +Compare WIND-A and WIND-B, which are selected by clicking, wordwise. +With prefix argument, DUMB-MODE, or on a non-windowing display, works as +follows: +If WIND-A is nil, use selected window. +If WIND-B is nil, use window next to WIND-A." t nil) + +(autoload 'ediff-windows-linewise "ediff" "\ +Compare WIND-A and WIND-B, which are selected by clicking, linewise. +With prefix argument, DUMB-MODE, or on a non-windowing display, works as +follows: +If WIND-A is nil, use selected window. +If WIND-B is nil, use window next to WIND-A." t nil) + +(autoload 'ediff-regions-wordwise "ediff" "\ +Run Ediff on a pair of regions in specified buffers. +Regions (i.e., point and mark) are assumed to be set in advance except +for the second region in the case both regions are from the same buffer. +In such a case the user is asked to interactively establish the second +region. +This function is effective only for relatively small regions, up to 200 +lines. For large regions, use `ediff-regions-linewise'." t nil) + +(autoload 'ediff-regions-linewise "ediff" "\ +Run Ediff on a pair of regions in specified buffers. +Regions (i.e., point and mark) are assumed to be set in advance except +for the second region in the case both regions are from the same buffer. +In such a case the user is asked to interactively establish the second +region. +Each region is enlarged to contain full lines. +This function is effective for large regions, over 100-200 +lines. For small regions, use `ediff-regions-wordwise'." t nil) + +(defalias 'ediff-merge 'ediff-merge-files) + +(autoload 'ediff-merge-files "ediff" "\ +Merge two files without ancestor." t nil) + +(autoload 'ediff-merge-files-with-ancestor "ediff" "\ +Merge two files with ancestor." t nil) + +(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor) + +(autoload 'ediff-merge-buffers "ediff" "\ +Merge buffers without ancestor." t nil) + +(autoload 'ediff-merge-buffers-with-ancestor "ediff" "\ +Merge buffers with ancestor." t nil) + +(autoload 'ediff-merge-revisions "ediff" "\ +Run Ediff by merging two revisions of a file. +The file is the optional FILE argument or the file visited by the current +buffer." t nil) + +(autoload 'ediff-merge-revisions-with-ancestor "ediff" "\ +Run Ediff by merging two revisions of a file with a common ancestor. +The file is the optional FILE argument or the file visited by the current +buffer." t nil) + +(autoload 'run-ediff-from-cvs-buffer "ediff" "\ +Run Ediff-merge on appropriate revisions of the selected file. +First run after `M-x cvs-update'. Then place the cursor on a line describing a +file and then run `run-ediff-from-cvs-buffer'." t nil) + +(autoload 'ediff-patch-file "ediff" "\ +Run Ediff by patching SOURCE-FILENAME. +If optional PATCH-BUF is given, use the patch in that buffer +and don't ask the user. +If prefix argument, then: if even argument, assume that the patch is in a +buffer. If odd -- assume it is in a file." t nil) + +(autoload 'ediff-patch-buffer "ediff" "\ +Run Ediff by patching the buffer specified at prompt. +Without the optional prefix ARG, asks if the patch is in some buffer and +prompts for the buffer or a file, depending on the answer. +With ARG=1, assumes the patch is in a file and prompts for the file. +With ARG=2, assumes the patch is in a buffer and prompts for the buffer. +PATCH-BUF is an optional argument, which specifies the buffer that contains the +patch. If not given, the user is prompted according to the prefix argument." t nil) + +(defalias 'epatch 'ediff-patch-file) + +(defalias 'epatch-buffer 'ediff-patch-buffer) + +(autoload 'ediff-revision "ediff" "\ +Run Ediff by comparing versions of a file. +The file is an optional FILE argument or the file entered at the prompt. +Default: the file visited by the current buffer. +Uses `vc.el' or `rcs.el' depending on `ediff-version-control-package'." t nil) + +(defalias 'erevision 'ediff-revision) + +(autoload 'ediff-version "ediff" "\ +Return string describing the version of Ediff. +When called interactively, displays the version." t nil) + +(autoload 'ediff-documentation "ediff" "\ +Display Ediff's manual. +With optional NODE, goes to that node." t nil) + +;;;*** + +(provide 'ediff-autoloads) diff --git a/xemacs-packages/lisp/ediff/auto-autoloads.elc b/xemacs-packages/lisp/ediff/auto-autoloads.elc new file mode 100644 index 0000000000000000000000000000000000000000..e591d2dc145a94afed532ae09f8b32a6c5ffe093 GIT binary patch literal 11790 zcmd^F+m77E5%pVa<|Pk#PivH9cYxt&u6q*#XeF&20lHx&K>;KK;tqReh~H?I8hz4zX8 zE?&GSCh;N(Lg|Zx6A>L=3gd|v&f_fa@-IJLctIrMNIU?^HF+Qg1JNJuj7K~DZ87Ne zHh7Y08ZX2Y(})Z6cp)!DhZmB=nR~DdLjOW8v;4vnx$q{Ln|PB$Zzi(~(hsK73*Iu1 zUHT`CJwNNpkY{63aU|0$0OLWwI}+=Omrv%RzttA4yYVFOLUAXJ6Pe~GE%Apvnp@mh zP6EHnGaQ`ck``7@(j9DSx{D-s&+Toy{ehy6lRQ`ifAn%<7i3tidY{knz^htj60eg< z?Bnn8Jb);EETT9U@=1{80xD86^tZc?vmQ*vx)=Fk{UBaOej?V?;`NH!&Ie*WPU|E| zJelw87#bm~&lp4ht!H@}L^C&(S(b>(w4ycWwc72r!*nuD!J_rJq2V=g>}93Zr=U`z z^JoZ9k{P)t%QTfy?vi=j5G!p%0-1j-8XrUygy44Q(+Cw(Y$GFfwoS&#<6g8iYTpx^pP3_pVQ8*=Jtf+)z{g^ZRN z#Gz%ip1(NvkH5cs_4C)~pT2zaD55`KeL(-deINhAMz7DaL~NKvkWF|vKuK)%Z}m;4 zGg*BREk$8jVtPOt_kA~89?+v$Z{3UIFl#{pw{N?b)A%@(X}8;LSzk(;@)ylP6CkYQ zIXt!e(sI>*(8K5>sKJ8Zv-dCm;)`eJKKtvJ&z?VOJ$*rsFX-{bOFX`!$5-_D>NOtU z(Bm6=eDf6^-+q1W)4#p_=GGEb#kJ;%_dICUDPBGnmr zt_G=`NrwV7Mhqqsed<`U^|YLzZu+;3p2S(CUQMZ zqqNh+kD9*%Mosh%9(qWVi&3YseHDRgouU5*^uQL zik_gOOmdHCl$9G)>NV&JFc;g(dTWn16LAx7WEgsp^oXN==|xK~Y-tbh}Yk)Ei9+(&H4ppMkbrI@DP0{>E` z#A0Ii&(k>63pKOk@oW}iD@61U)QFudKOxQV2eFgM5aAVRbeSI(`=rh*mN~MhGX0Xg z#j2p?Vk=oD?sOSVC{JyJOn$7DvXa8&Dr%gGe5H8pHf=PtP!A%;A#Ky_M&DzR$cJ4s z=FC;r7np+!NzMziW^ogU({APsK{SnF@k2AWK5;L|JPs zqqL7r+x?ZZUZj3n<5k=1{Ew8>LJoKS*GS-ogYAvB$T`8SWLRd}LeVyiNR<9)OWcJ@ zQ7v$RRO(*%TEsjS8S;7HMnT5Br|RJVwNlrCOHJlpGy{(2Qs`Ww190a2;>b$_?*J%! zd<2Hp0;IK$uF%e2tTo1@{ngcOj8SZAv!A~-?uq>+ zsyq$=NIpGOBSA_F;f=E+u3f*e=k5wJ9RIw$O3_TK*_C?T+8*1S##K%^=Xn(_n%m`0 z$?nRj?1puIqh7CH@UwH}&!2sPtoL(NB`wNxi=u~-HPkN1g6IePm3F`WMom$q3>GuU zGlujsQM-t9pNeV%b%-E~;7oX5CLMw58E;d>CH$XBfCklmgs7he=uK!cfaE&SnF<|$ zvGeE|lrOA_AXgEMSR<{S1(6r7(vuq3&{KbVQ0NH=*r?j2M1W3fI^y#EYuEPnH45~@ zN*w4B4UVJUcEQmu<_x_KTKbV<44klnONEw(M1^b`Gg`QnsL_L)xEYVnlx}DOp_zcg zasO1cnVbaqTSr{IzTan<;K!iD{Ru?2Xr|l?hDMy2dq>hCz+|)^NAwSZ%0ZmZyF%Q< zd%z*}0h<}82pzG%_u<|j?f_947xM^Hp6LNN@=21aJm8{=PXuh9lt2k?s=_9A2=t(4 zIAZJ1(0WLvzY0gziW;Wf9Q0P27GsLGf;FCXH`uNk*F%_9CEAJ7n5`%Rxr#5mi$ie4 zry>VMOeMvkD~15IQbUDm(9<%iQJTQ4ISNrcAPa()98!G-o!_RoZr*COk<+5-B}?8g zrplM-Q|=u~G}$6-eBNY&_E>(FBCT|_uF!GM+Kp^qfr_l!Ps{%bAmb1~SsxXEdLjBq6vQ=3Ll41jr3t7tLm+j4IBryxmiUi=wBh38 z;r8h$E&SV3k4m}vqdHE_=4g>Ne4L7$pPGkP3p1)bRi;#I=HtzNnIzRd z#$1HR;pRx(WGaO#1UO5F)i5cRlsjst2jT9mD|>hE-QITrQGsTqspGL%s=S3cnkZ3( zRDpmN<-E7DV^dJ2aI8QN&|;%4H#-)~(Imzp255)NELu}B8gC2UG?^_|N2gH70lb3c zaVT8HOSpt-O{ic#jh89RyL7 zYOVvLID#b9b|zQW1w7A$%Gb-BX&i=VN$*g-q9s!KXb16|QZg-vnuE(4C9O_d6`A@f zBKd^sWIfTU)JYLqE$3R8+8kD@n!%6Lm+4Xe^z~&{Qs2-wH>~#0`AehTsr3x?gXk;( zJ6@K^NiYrQR9zq9IQ#nRdeD{Kj!0tUz#L~5UV7LD#8B^M844Gl?0Z1K;B#fqKcYy4 z9d06%9B4{ahN&`n#gkZ48b0v=D5{5OUu0QmTJAm3XUi}um z-k9}F+n?suTcgcUVf$+GVYZrT&cSIfC+K6HpXWHiRXKVifnCvOR=by?uSMkT-k_8P z6~JI6gEBond-m$CSjYT!e_-|giVmNyl9iCOobn8?@`>fIa$ubdwa7Z!ao4Sq(w{1` z8By2Cu;QD;-UBVQ47WE6ETFGl>AE00Ag$2WP6jXfDb)GZ$6=fvl4i&~ zD2~#7q8P14ZUh&}10@Xfl_}{AoQ{GpJ-yRc3LG7rPt{h*zOJuvuPi&UhVj5kh2Omf z)h5MO5HA*#)R;=_zp=D;7;CdNhPAaa7?ZO<3NSd8$tG!VKp^oP zwl6h`KpOG9k1@Hcl4075U7B23x)!@mrE5TTdst@cIP zlxg)l)XPT$AF3^SvMR~JU`%T<;ZFKT`4AF&jdr>fE@B-<*Sw?O z>sMTSv}K>M*!m)g)MBk14w3>+izHWBE(JECEA*(>zPtY+I)oXreyqB_v<%lG&CF1v zqb5Ykq@#jniYK+e4nUR2$R{HLXf&M{Wyhp#u1vt}cj(Y4ZK|-NO=f8cLwqfI$w{HU zn1s5ToOiC8L`$`58uh8`R6vBrPob64hOQAx`; z*{RYTVkh;FQ&tdiN7i?>T3eM9DvW664U~+3=)ss$xpHkaHG99lN1@r+pVh0PR<&D1 zfFa!|RHq*HN$IL>##XdCVbcy)*=5kyqoWF8Tup=cs=A}L!%Aa;S8qoeuU&Og_xNan z3%YB>;Bh*k%ere-jOyH6i;nA&-1RqCeruslDaFL*dVK5maduwp$##BLjL>I$-;%ZCGT}o@#;4D8jtf_!5RF4cy8m1$cHn;MgkGUlk6eW)Gie=6SirDY z0nX`0jcW-DzSyGuxp13X++3KUok}GU`$vS!w5wQG@4_?$*ce*Jb?_R#Gpp5Ru0dpN F=U<4DrP2TZ literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/custom-load.el b/xemacs-packages/lisp/ediff/custom-load.el new file mode 100644 index 00000000..45b71e64 --- /dev/null +++ b/xemacs-packages/lisp/ediff/custom-load.el @@ -0,0 +1,18 @@ +;;; custom-load.el --- automatically extracted custom dependencies + +;;; Code: + +(autoload 'custom-add-loads "cus-load") + +(custom-add-loads 'tools '("ediff")) +(custom-add-loads 'ediff-hook '("ediff-init" "ediff-mult")) +(custom-add-loads 'ediff-diff '("ediff-diff")) +(custom-add-loads 'ediff-window '("ediff-help" "ediff-wind")) +(custom-add-loads 'frames '("ediff-wind")) +(custom-add-loads 'ediff-ptch '("ediff-ptch")) +(custom-add-loads 'ediff-merge '("ediff-init" "ediff-merg")) +(custom-add-loads 'ediff-highlighting '("ediff-init")) +(custom-add-loads 'ediff-mult '("ediff-mult")) +(custom-add-loads 'ediff '("ediff-diff" "ediff-init" "ediff-mult" "ediff-ptch" "ediff-tbar" "ediff-wind" "ediff")) + +;;; custom-load.el ends here diff --git a/xemacs-packages/lisp/ediff/custom-load.elc b/xemacs-packages/lisp/ediff/custom-load.elc new file mode 100644 index 0000000000000000000000000000000000000000..8f2672c5f254bf0e414cad6abe772b17ce2909a1 GIT binary patch literal 1085 zcmZWn$&S=85bY~{<^xK;Omaxlof($yz96CDGzTOOATdZdvD2~IiG%IXGyDMaSq%HW z!}s8FIvE0yQc2Z&uBunA)#1_2%ah4ux>~IuS5+e@lq~0XWW*ud%kSwv>*yMy)G&fO0 z^9@~dlW-=ABFS50RTW7^S0Eu<^#&g0-C921ad=g*JH+4+l?XkWcX`{pg$ckj`D z_=xt?XS83wqW$(A?T?>mfBiltPYK+otyQ=huBKlT%9!uR0C5rjOTa264Ftq56bZq9 zqf)6&AB;pTEP;*@RjsrG4VQ4Bp)(*`Q8Tq2u#(GWNP(Cm7MfOWBX*^uU9_v;;KKF@ zIz!@$>op&sacd45c%@jE(!JK*_?X^nL?r|Ax2z%P74^c$rEm&8;`{3zn^8R=UegXC K;RDzYr+)wlRBvkl literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/ediff-diff.el b/xemacs-packages/lisp/ediff/ediff-diff.el new file mode 100644 index 00000000..013ed907 --- /dev/null +++ b/xemacs-packages/lisp/ediff/ediff-diff.el @@ -0,0 +1,1559 @@ +;;; ediff-diff.el --- diff-related utilities + +;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +;; 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +;; Author: Michael Kifer + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;;; Code: + + +;; compiler pacifier +(defvar ediff-default-variant) +(defvar null-device) +(defvar longlines-mode) + +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + (or (featurep 'ediff-util) + (load "ediff-util.el" nil nil 'nosuffix)) + )) +;; end pacifier + +(require 'ediff-init) + +(defgroup ediff-diff nil + "Diff related utilities." + :prefix "ediff-" + :group 'ediff) + +;; these two must be here to prevent ediff-test-utility from barking +(defcustom ediff-diff-program "diff" + "*Program to use for generating the differential of the two files." + :type 'string + :group 'ediff-diff) +(defcustom ediff-diff3-program "diff3" + "*Program to be used for three-way comparison. +Must produce output compatible with Unix's diff3 program." + :type 'string + :group 'ediff-diff) + + +;; The following functions must precede all defcustom-defined variables. + +;; The following functions needed for setting diff/diff3 options +;; test if diff supports the --binary option +(defsubst ediff-test-utility (diff-util option &optional files) + (eq 0 (apply 'call-process + (append (list diff-util nil nil nil option) files)))) + +(defun ediff-diff-mandatory-option (diff-util) + (let ((file (if (boundp 'null-device) null-device "/dev/null"))) + (cond ((not (memq system-type '(ms-dos windows-nt windows-95))) + "") + ((and (string= diff-util ediff-diff-program) + (ediff-test-utility + ediff-diff-program "--binary" (list file file))) + "--binary") + ((and (string= diff-util ediff-diff3-program) + (ediff-test-utility + ediff-diff3-program "--binary" (list file file file))) + "--binary") + (t "")))) + +;; make sure that mandatory options are added even if the user changes +;; ediff-diff-options or ediff-diff3-options in the customization widget +(defun ediff-reset-diff-options (symb val) + (let* ((diff-program + (if (eq symb 'ediff-diff-options) + ediff-diff-program + ediff-diff3-program)) + (mandatory-option (ediff-diff-mandatory-option diff-program)) + (spacer (if (string-equal mandatory-option "") "" " "))) + (set symb + (if (string-match mandatory-option val) + val + (concat mandatory-option spacer val))) + )) + + +(defcustom ediff-shell + (cond ((eq system-type 'emx) "cmd") ; OS/2 + ((memq system-type '(ms-dos windows-nt windows-95)) + shell-file-name) ; no standard name on MS-DOS + ((memq system-type '(vax-vms axp-vms)) "*dcl*") ; VMS + (t "sh")) ; UNIX + "*The shell used to run diff and patch. +If user's .profile or .cshrc files are set up correctly, any shell +will do. However, some people set $prompt or other things +incorrectly, which leads to undesirable output messages. These may +cause Ediff to fail. In such a case, set `ediff-shell' to a shell that +you are not using or, better, fix your shell's startup file." + :type 'string + :group 'ediff-diff) + +(defcustom ediff-cmp-program "cmp" + "*Utility to use to determine if two files are identical. +It must return code 0, if its arguments are identical files." + :type 'string + :group 'ediff-diff) + +(defcustom ediff-cmp-options nil + "*Options to pass to `ediff-cmp-program'. +If GNU diff is used as `ediff-cmp-program', then the most useful options +are `-I REGEXP', to ignore changes whose lines match the REGEXP." + :type '(repeat string) + :group 'ediff-diff) + +(defcustom ediff-diff-options "" + "*Options to pass to `ediff-diff-program'. +If Unix diff is used as `ediff-diff-program', then a useful option is +`-w', to ignore space, and `-i', to ignore case of letters. +Options `-c' and `-i' are not allowed. Case sensitivity can be toggled +interactively using [ediff-toggle-ignore-case]" + :set 'ediff-reset-diff-options + :type 'string + :group 'ediff-diff) + +(ediff-defvar-local ediff-ignore-case nil + "*If t, skip over difference regions that differ only in letter case. +This variable can be set either in .emacs or toggled interactively. +Use `setq-default' if setting it in .emacs") + +(defcustom ediff-ignore-case-option "-i" + "*Option that causes the diff program to ignore case of letters." + :type 'string + :group 'ediff-diff) + +(defcustom ediff-ignore-case-option3 "" + "*Option that causes the diff3 program to ignore case of letters. +GNU diff3 doesn't have such an option." + :type 'string + :group 'ediff-diff) + +;; the actual options used in comparison +(ediff-defvar-local ediff-actual-diff-options "" "") + +(defcustom ediff-custom-diff-program ediff-diff-program + "*Program to use for generating custom diff output for saving it in a file. +This output is not used by Ediff internally." + :type 'string + :group 'ediff-diff) +(defcustom ediff-custom-diff-options "-c" + "*Options to pass to `ediff-custom-diff-program'." + :type 'string + :group 'ediff-diff) + +;;; Support for diff3 + +(defvar ediff-match-diff3-line "^====\\(.?\\)\C-m?$" + "Pattern to match lines produced by diff3 that describe differences.") +(defcustom ediff-diff3-options "" + "*Options to pass to `ediff-diff3-program'." + :set 'ediff-reset-diff-options + :type 'string + :group 'ediff-diff) + +;; the actual options used in comparison +(ediff-defvar-local ediff-actual-diff3-options "" "") + +(defcustom ediff-diff3-ok-lines-regexp + "^\\([1-3]:\\|====\\| \\|.*Warning *:\\|.*No newline\\|.*missing newline\\|^\C-m$\\)" + "*Regexp that matches normal output lines from `ediff-diff3-program'. +Lines that do not match are assumed to be error messages." + :type 'regexp + :group 'ediff-diff) + +;; keeps the status of the current diff in 3-way jobs. +;; the status can be =diff(A), =diff(B), or =diff(A+B) +(ediff-defvar-local ediff-diff-status "" "") + + +;;; Fine differences + +(ediff-defvar-local ediff-auto-refine (if (ediff-has-face-support-p) 'on 'nix) + "If `on', Ediff auto-highlights fine diffs for the current diff region. +If `off', auto-highlighting is not used. If `nix', no fine diffs are shown +at all, unless the user force-refines the region by hitting `*'. + +This variable can be set either in .emacs or toggled interactively. +Use `setq-default' if setting it in .emacs") + +(ediff-defvar-local ediff-ignore-similar-regions nil + "*If t, skip over difference regions that differ only in the white space and line breaks. +This variable can be set either in .emacs or toggled interactively. +Use `setq-default' if setting it in .emacs") + +(ediff-defvar-local ediff-auto-refine-limit 14000 + "*Auto-refine only the regions of this size \(in bytes\) or less.") + +;;; General + +(defvar ediff-diff-ok-lines-regexp + (concat + "^\\(" + "[0-9,]+[acd][0-9,]+\C-m?$" + "\\|[<>] " + "\\|---" + "\\|.*Warning *:" + "\\|.*No +newline" + "\\|.*missing +newline" + "\\|^\C-m?$" + "\\)") + "Regexp that matches normal output lines from `ediff-diff-program'. +This is mostly lifted from Emerge, except that Ediff also considers +warnings and `Missing newline'-type messages to be normal output. +Lines that do not match are assumed to be error messages.") + +(defvar ediff-match-diff-line + (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)")) + (concat "^" x "\\([acd]\\)" x "\C-m?$")) + "Pattern to match lines produced by diff that describe differences.") + +(ediff-defvar-local ediff-setup-diff-regions-function nil + "value is a function symbol depending on the kind of job is to be done. +For 2-way jobs and for ediff-merge, it should be `ediff-setup-diff-regions'. +For jobs requiring diff3, it should be `ediff-setup-diff-regions3'. + +The function should take three mandatory arguments, file-A, file-B, and +file-C. It may ignore file C for diff2 jobs. It should also take +one optional arguments, diff-number to refine.") + + +;;; Functions + +;; Generate the difference vector and overlays for the two files +;; With optional arg REG-TO-REFINE, refine this region. +;; File-C argument is not used here. It is there just because +;; ediff-setup-diff-regions is called via a funcall to +;; ediff-setup-diff-regions-function, which can also have the value +;; ediff-setup-diff-regions3, which takes 4 arguments. +(defun ediff-setup-diff-regions (file-A file-B file-C) + ;; looking for '-c', '-i', or a 'c', 'i' among clustered non-long options + (if (string-match "^-[ci]\\| -[ci]\\|\\(^\\| \\)-[^- ]+[ci]" + ediff-diff-options) + (error "Options `-c' and `-i' are not allowed in `ediff-diff-options'")) + + ;; create, if it doesn't exist + (or (ediff-buffer-live-p ediff-diff-buffer) + (setq ediff-diff-buffer + (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*")))) + (ediff-make-diff2-buffer ediff-diff-buffer file-A file-B) + (ediff-prepare-error-list ediff-diff-ok-lines-regexp ediff-diff-buffer) + (ediff-convert-diffs-to-overlays + (ediff-extract-diffs + ediff-diff-buffer ediff-word-mode ediff-narrow-bounds))) + +;; Run the diff program on FILE1 and FILE2 and put the output in DIFF-BUFFER +;; Return the size of DIFF-BUFFER +;; The return code isn't used in the program at present. +(defun ediff-make-diff2-buffer (diff-buffer file1 file2) + (let ((file1-size (ediff-file-size file1)) + (file2-size (ediff-file-size file2))) + (cond ((not (numberp file1-size)) + (message "Can't find file: %s" + (ediff-abbreviate-file-name file1)) + (sit-for 2) + ;; 1 is an error exit code + 1) + ((not (numberp file2-size)) + (message "Can't find file: %s" + (ediff-abbreviate-file-name file2)) + (sit-for 2) + ;; 1 is an error exit code + 1) + (t (message "Computing differences between %s and %s ..." + (file-name-nondirectory file1) + (file-name-nondirectory file2)) + ;; this erases the diff buffer automatically + (ediff-exec-process ediff-diff-program + diff-buffer + 'synchronize + ediff-actual-diff-options file1 file2) + (message "") + (ediff-with-current-buffer diff-buffer + (buffer-size)))))) + + + +;; If file-A/B/C is nil, do 2-way comparison with the non-nil buffers +;; This function works for diff3 and diff2 jobs +(defun ediff-setup-fine-diff-regions (file-A file-B file-C reg-num) + (or (ediff-buffer-live-p ediff-fine-diff-buffer) + (setq ediff-fine-diff-buffer + (get-buffer-create + (ediff-unique-buffer-name "*ediff-fine-diff" "*")))) + + (let (diff3-job diff-program diff-options ok-regexp diff-list) + (setq diff3-job ediff-3way-job + diff-program (if diff3-job ediff-diff3-program ediff-diff-program) + diff-options (if diff3-job + ediff-actual-diff3-options + ediff-actual-diff-options) + ok-regexp (if diff3-job + ediff-diff3-ok-lines-regexp + ediff-diff-ok-lines-regexp)) + + (ediff-message-if-verbose "Refining difference region %d ..." (1+ reg-num)) + (ediff-exec-process diff-program ediff-fine-diff-buffer 'synchronize + diff-options + ;; The shuffle below is because we can compare 3-way + ;; or in several 2-way fashions, like fA fC, fA fB, + ;; or fB fC. + (if file-A file-A file-B) + (if file-B file-B file-A) + (if diff3-job + (if file-C file-C file-B)) + ) ; exec process + + (ediff-prepare-error-list ok-regexp ediff-fine-diff-buffer) + (ediff-message-if-verbose + "") + ;; "Refining difference region %d ... done" (1+ reg-num)) + + (setq diff-list + (if diff3-job + (ediff-extract-diffs3 + ediff-fine-diff-buffer '3way-comparison 'word-mode) + (ediff-extract-diffs ediff-fine-diff-buffer 'word-mode))) + ;; fixup diff-list + (if diff3-job + (cond ((not file-A) + (mapcar (lambda (elt) + (aset elt 0 nil) + (aset elt 1 nil)) + (cdr diff-list))) + ((not file-B) + (mapcar (lambda (elt) + (aset elt 2 nil) + (aset elt 3 nil)) + (cdr diff-list))) + ((not file-C) + (mapcar (lambda (elt) + (aset elt 4 nil) + (aset elt 5 nil)) + (cdr diff-list))) + )) + + (ediff-convert-fine-diffs-to-overlays diff-list reg-num) + )) + + +(defun ediff-prepare-error-list (ok-regexp diff-buff) + (or (ediff-buffer-live-p ediff-error-buffer) + (setq ediff-error-buffer + (get-buffer-create (ediff-unique-buffer-name + "*ediff-errors" "*")))) + (ediff-with-current-buffer ediff-error-buffer + (erase-buffer) + (insert (ediff-with-current-buffer diff-buff (buffer-string))) + (goto-char (point-min)) + (delete-matching-lines ok-regexp) + (if (memq system-type '(vax-vms axp-vms)) + (delete-matching-lines "^$"))) + ;; If diff reports errors, show them then quit. + (if (/= 0 (ediff-with-current-buffer ediff-error-buffer (buffer-size))) + (let ((ctl-buf ediff-control-buffer) + (error-buf ediff-error-buffer)) + (ediff-skip-unsuitable-frames) + (switch-to-buffer error-buf) + (ediff-kill-buffer-carefully ctl-buf) + (error "Errors in diff output. Diff output is in %S" diff-buff)))) + +;; BOUNDS specifies visibility bounds to use. +;; WORD-MODE tells whether we are in the word-mode or not. +;; If WORD-MODE, also construct vector of diffs using word numbers. +;; Else, use point values. +;; This function handles diff-2 jobs including the case of +;; merging buffers and files without ancestor. +(defun ediff-extract-diffs (diff-buffer word-mode &optional bounds) + (let ((A-buffer ediff-buffer-A) + (B-buffer ediff-buffer-B) + (C-buffer ediff-buffer-C) + (a-prev 1) ; this is needed to set the first diff line correctly + (a-prev-pt nil) + (b-prev 1) + (b-prev-pt nil) + (c-prev 1) + (c-prev-pt nil) + diff-list shift-A shift-B + ) + + ;; diff list contains word numbers, unless changed later + (setq diff-list (cons (if word-mode 'words 'points) + diff-list)) + ;; we don't use visibility bounds for buffer C when merging + (if bounds + (setq shift-A + (ediff-overlay-start + (ediff-get-value-according-to-buffer-type 'A bounds)) + shift-B + (ediff-overlay-start + (ediff-get-value-according-to-buffer-type 'B bounds)))) + + ;; reset point in buffers A/B/C + (ediff-with-current-buffer A-buffer + (goto-char (if shift-A shift-A (point-min)))) + (ediff-with-current-buffer B-buffer + (goto-char (if shift-B shift-B (point-min)))) + (if (ediff-buffer-live-p C-buffer) + (ediff-with-current-buffer C-buffer + (goto-char (point-min)))) + + (ediff-with-current-buffer diff-buffer + (goto-char (point-min)) + (while (re-search-forward ediff-match-diff-line nil t) + (let* ((a-begin (string-to-number (buffer-substring (match-beginning 1) + (match-end 1)))) + (a-end (let ((b (match-beginning 3)) + (e (match-end 3))) + (if b + (string-to-number (buffer-substring b e)) + a-begin))) + (diff-type (buffer-substring (match-beginning 4) (match-end 4))) + (b-begin (string-to-number (buffer-substring (match-beginning 5) + (match-end 5)))) + (b-end (let ((b (match-beginning 7)) + (e (match-end 7))) + (if b + (string-to-number (buffer-substring b e)) + b-begin))) + a-begin-pt a-end-pt b-begin-pt b-end-pt + c-begin c-end c-begin-pt c-end-pt) + ;; fix the beginning and end numbers, because diff is somewhat + ;; strange about how it numbers lines + (if (string-equal diff-type "a") + (setq b-end (1+ b-end) + a-begin (1+ a-begin) + a-end a-begin) + (if (string-equal diff-type "d") + (setq a-end (1+ a-end) + b-begin (1+ b-begin) + b-end b-begin) + ;; (string-equal diff-type "c") + (setq a-end (1+ a-end) + b-end (1+ b-end)))) + + (if (eq ediff-default-variant 'default-B) + (setq c-begin b-begin + c-end b-end) + (setq c-begin a-begin + c-end a-end)) + + ;; compute main diff vector + (if word-mode + ;; make diff-list contain word numbers + (setq diff-list + (nconc diff-list + (list + (if (ediff-buffer-live-p C-buffer) + (vector (- a-begin a-prev) (- a-end a-begin) + (- b-begin b-prev) (- b-end b-begin) + (- c-begin c-prev) (- c-end c-begin) + nil nil ; dummy ancestor + nil ; state of diff + nil ; state of merge + nil ; state of ancestor + ) + (vector (- a-begin a-prev) (- a-end a-begin) + (- b-begin b-prev) (- b-end b-begin) + nil nil ; dummy buf C + nil nil ; dummy ancestor + nil ; state of diff + nil ; state of merge + nil ; state of ancestor + )) + )) + a-prev a-end + b-prev b-end + c-prev c-end) + ;; else convert lines to points + (ediff-with-current-buffer A-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + ;; we must disable and then restore longlines-mode + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or a-prev-pt shift-A (point-min))) + (forward-line (- a-begin a-prev)) + (setq a-begin-pt (point)) + (forward-line (- a-end a-begin)) + (setq a-end-pt (point) + a-prev a-end + a-prev-pt a-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + )) + (ediff-with-current-buffer B-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or b-prev-pt shift-B (point-min))) + (forward-line (- b-begin b-prev)) + (setq b-begin-pt (point)) + (forward-line (- b-end b-begin)) + (setq b-end-pt (point) + b-prev b-end + b-prev-pt b-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + )) + (if (ediff-buffer-live-p C-buffer) + (ediff-with-current-buffer C-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or c-prev-pt (point-min))) + (forward-line (- c-begin c-prev)) + (setq c-begin-pt (point)) + (forward-line (- c-end c-begin)) + (setq c-end-pt (point) + c-prev c-end + c-prev-pt c-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + ))) + (setq diff-list + (nconc + diff-list + (list + (if (ediff-buffer-live-p C-buffer) + (vector + a-begin-pt a-end-pt b-begin-pt b-end-pt + c-begin-pt c-end-pt + nil nil ; dummy ancestor + ;; state of diff + ;; shows which buff is different from the other two + (if (eq ediff-default-variant 'default-B) 'A 'B) + ediff-default-variant ; state of merge + nil ; state of ancestor + ) + (vector a-begin-pt a-end-pt + b-begin-pt b-end-pt + nil nil ; dummy buf C + nil nil ; dummy ancestor + nil nil ; dummy state of diff & merge + nil ; dummy state of ancestor + ))) + ))) + + ))) ; end ediff-with-current-buffer + diff-list + )) + + +(defun ediff-convert-diffs-to-overlays (diff-list) + (ediff-set-diff-overlays-in-one-buffer 'A diff-list) + (ediff-set-diff-overlays-in-one-buffer 'B diff-list) + (if ediff-3way-job + (ediff-set-diff-overlays-in-one-buffer 'C diff-list)) + (if ediff-merge-with-ancestor-job + (ediff-set-diff-overlays-in-one-buffer 'Ancestor diff-list)) + ;; set up vector showing the status of merge regions + (if ediff-merge-job + (setq ediff-state-of-merge + (vconcat + (mapcar (lambda (elt) + (let ((state-of-merge (aref elt 9)) + (state-of-ancestor (aref elt 10))) + (vector + ;; state of merge: prefers/default-A/B or combined + (if state-of-merge (format "%S" state-of-merge)) + ;; whether the ancestor region is empty + state-of-ancestor))) + ;; the first elt designates type of list + (cdr diff-list)) + ))) + (message "Processing difference regions ... done")) + + +(defun ediff-set-diff-overlays-in-one-buffer (buf-type diff-list) + (let* ((current-diff -1) + (buff (ediff-get-buffer buf-type)) + (ctl-buf ediff-control-buffer) + ;; ediff-extract-diffs puts the type of diff-list as the first elt + ;; of this list. The type is either 'points or 'words + (diff-list-type (car diff-list)) + (shift (ediff-overlay-start + (ediff-get-value-according-to-buffer-type + buf-type ediff-narrow-bounds))) + (limit (ediff-overlay-end + (ediff-get-value-according-to-buffer-type + buf-type ediff-narrow-bounds))) + diff-overlay-list list-element total-diffs + begin end pt-saved overlay state-of-diff) + + (setq diff-list (cdr diff-list)) ; discard diff list type + (setq total-diffs (length diff-list)) + + ;; shift, if necessary + (ediff-with-current-buffer buff (setq pt-saved shift)) + + (while diff-list + (setq current-diff (1+ current-diff) + list-element (car diff-list) + begin (aref list-element (cond ((eq buf-type 'A) 0) + ((eq buf-type 'B) 2) + ((eq buf-type 'C) 4) + (t 6))) ; Ancestor + end (aref list-element (cond ((eq buf-type 'A) 1) + ((eq buf-type 'B) 3) + ((eq buf-type 'C) 5) + (t 7))) ; Ancestor + state-of-diff (aref list-element 8) + ) + + (cond ((and (not (eq buf-type state-of-diff)) + (not (eq buf-type 'Ancestor)) + (memq state-of-diff '(A B C))) + (setq state-of-diff + (car (delq buf-type (delq state-of-diff (list 'A 'B 'C))))) + (setq state-of-diff (format "=diff(%S)" state-of-diff)) + ) + (t (setq state-of-diff nil))) + + ;; Put overlays at appropriate places in buffer + ;; convert word numbers to points, if necessary + (if (eq diff-list-type 'words) + (progn + (ediff-with-current-buffer buff (goto-char pt-saved)) + (ediff-with-current-buffer ctl-buf + (setq begin (ediff-goto-word (1+ begin) buff) + end (ediff-goto-word end buff 'end))) + (if (> end limit) (setq end limit)) + (if (> begin end) (setq begin end)) + (setq pt-saved (ediff-with-current-buffer buff (point))))) + (setq overlay (ediff-make-bullet-proof-overlay begin end buff)) + + (ediff-overlay-put overlay 'priority ediff-shadow-overlay-priority) + (ediff-overlay-put overlay 'ediff-diff-num current-diff) + (if (and (ediff-has-face-support-p) + ediff-use-faces ediff-highlight-all-diffs) + (ediff-set-overlay-face + overlay (ediff-background-face buf-type current-diff))) + + (if (= 0 (mod current-diff 10)) + (message "Buffer %S: Processing difference region %d of %d" + buf-type current-diff total-diffs)) + ;; Record all overlays for this difference. + ;; The 2-d elt, nil, is a place holder for the fine diff vector. + ;; The 3-d elt, nil, is a place holder for no-fine-diffs flag. + ;; The 4-th elt says which diff region is different from the other two + ;; (3-way jobs only). + (setq diff-overlay-list + (nconc + diff-overlay-list + (list (vector overlay nil nil state-of-diff))) + diff-list + (cdr diff-list)) + ) ; while + + (set (ediff-get-symbol-from-alist buf-type ediff-difference-vector-alist) + (vconcat diff-overlay-list)) + )) + +;; `n' is the diff region to work on. Default is ediff-current-difference. +;; if `flag' is 'noforce then make fine-diffs only if this region's fine +;; diffs have not been computed before. +;; if `flag' is 'skip then don't compute fine diffs for this region. +(defun ediff-make-fine-diffs (&optional n flag) + (or n (setq n ediff-current-difference)) + + (if (< ediff-number-of-differences 1) + (error ediff-NO-DIFFERENCES)) + + (if ediff-word-mode + (setq flag 'skip + ediff-auto-refine 'nix)) + + (or (< n 0) + (>= n ediff-number-of-differences) + ;; n is within the range + (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer)) + (file-A ediff-temp-file-A) + (file-B ediff-temp-file-B) + (file-C ediff-temp-file-C) + (empty-A (ediff-empty-diff-region-p n 'A)) + (empty-B (ediff-empty-diff-region-p n 'B)) + (empty-C (ediff-empty-diff-region-p n 'C)) + (whitespace-A (ediff-whitespace-diff-region-p n 'A)) + (whitespace-B (ediff-whitespace-diff-region-p n 'B)) + (whitespace-C (ediff-whitespace-diff-region-p n 'C)) + cumulative-fine-diff-length) + + (cond ;; If one of the regions is empty (or 2 in 3way comparison) + ;; then don't refine. + ;; If the region happens to be entirely whitespace or empty then + ;; mark as such. + ((> (length (delq nil (list empty-A empty-B empty-C))) 1) + (if (and (ediff-looks-like-combined-merge n) + ediff-merge-job) + (ediff-set-fine-overlays-in-one-buffer 'C nil n)) + (if ediff-3way-comparison-job + (ediff-message-if-verbose + "Region %d is empty in all buffers but %S" + (1+ n) + (cond ((not empty-A) 'A) + ((not empty-B) 'B) + ((not empty-C) 'C))) + (ediff-message-if-verbose + "Region %d in buffer %S is empty" + (1+ n) + (cond (empty-A 'A) + (empty-B 'B) + (empty-C 'C))) + ) + ;; if all regions happen to be whitespace + (if (and whitespace-A whitespace-B whitespace-C) + ;; mark as space only + (ediff-mark-diff-as-space-only n t) + ;; if some regions are white and others don't, then mark as + ;; non-white-space-only + (ediff-mark-diff-as-space-only n nil))) + + ;; don't compute fine diffs if diff vector exists + ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n 'A)) + (if (ediff-no-fine-diffs-p n) + (message + "Only white-space differences in region %d %s" + (1+ n) + (cond ((eq (ediff-no-fine-diffs-p n) 'A) + "in buffers B & C") + ((eq (ediff-no-fine-diffs-p n) 'B) + "in buffers A & C") + ((eq (ediff-no-fine-diffs-p n) 'C) + "in buffers A & B") + (t ""))))) + ;; don't compute fine diffs for this region + ((eq flag 'skip) + (or (ediff-get-fine-diff-vector n 'A) + (memq ediff-auto-refine '(off nix)) + (ediff-message-if-verbose + "Region %d exceeds the auto-refinement limit. Type `%s' to refine" + (1+ n) + (substitute-command-keys + "\\[ediff-make-or-kill-fine-diffs]") + ))) + (t + ;; recompute fine diffs + (ediff-wordify + (ediff-get-diff-posn 'A 'beg n) + (ediff-get-diff-posn 'A 'end n) + ediff-buffer-A + tmp-buffer + ediff-control-buffer) + (setq file-A + (ediff-make-temp-file tmp-buffer "fineDiffA" file-A)) + + (ediff-wordify + (ediff-get-diff-posn 'B 'beg n) + (ediff-get-diff-posn 'B 'end n) + ediff-buffer-B + tmp-buffer + ediff-control-buffer) + (setq file-B + (ediff-make-temp-file tmp-buffer "fineDiffB" file-B)) + + (if ediff-3way-job + (progn + (ediff-wordify + (ediff-get-diff-posn 'C 'beg n) + (ediff-get-diff-posn 'C 'end n) + ediff-buffer-C + tmp-buffer + ediff-control-buffer) + (setq file-C + (ediff-make-temp-file + tmp-buffer "fineDiffC" file-C)))) + + ;; save temp file names. + (setq ediff-temp-file-A file-A + ediff-temp-file-B file-B + ediff-temp-file-C file-C) + + ;; set the new vector of fine diffs, if none exists + (cond ((and ediff-3way-job whitespace-A) + (ediff-setup-fine-diff-regions nil file-B file-C n)) + ((and ediff-3way-job whitespace-B) + (ediff-setup-fine-diff-regions file-A nil file-C n)) + ((and ediff-3way-job + ;; In merge-jobs, whitespace-C is t, since + ;; ediff-empty-diff-region-p returns t in this case + whitespace-C) + (ediff-setup-fine-diff-regions file-A file-B nil n)) + (t + (ediff-setup-fine-diff-regions file-A file-B file-C n))) + + (setq cumulative-fine-diff-length + (+ (length (ediff-get-fine-diff-vector n 'A)) + (length (ediff-get-fine-diff-vector n 'B)) + ;; in merge jobs, the merge buffer is never refined + (if (and file-C (not ediff-merge-job)) + (length (ediff-get-fine-diff-vector n 'C)) + 0))) + + (cond ((or + ;; all regions are white space + (and whitespace-A whitespace-B whitespace-C) + ;; none is white space and no fine diffs detected + (and (not whitespace-A) + (not whitespace-B) + (not (and ediff-3way-job whitespace-C)) + (eq cumulative-fine-diff-length 0))) + (ediff-mark-diff-as-space-only n t) + (ediff-message-if-verbose + "Only white-space differences in region %d" (1+ n))) + ((eq cumulative-fine-diff-length 0) + (ediff-message-if-verbose + "Only white-space differences in region %d %s" + (1+ n) + (cond (whitespace-A (ediff-mark-diff-as-space-only n 'A) + "in buffers B & C") + (whitespace-B (ediff-mark-diff-as-space-only n 'B) + "in buffers A & C") + (whitespace-C (ediff-mark-diff-as-space-only n 'C) + "in buffers A & B")))) + (t + (ediff-mark-diff-as-space-only n nil))) + ) + ) ; end cond + (ediff-set-fine-diff-properties n) + ))) + +;; Interface to ediff-make-fine-diffs. Checks for auto-refine limit, etc. +(defun ediff-install-fine-diff-if-necessary (n) + (cond ((and (eq ediff-auto-refine 'on) + ediff-use-faces + (not (eq ediff-highlighting-style 'off)) + (not (eq ediff-highlighting-style 'ascii))) + (if (and + (> ediff-auto-refine-limit + (- (ediff-get-diff-posn 'A 'end n) + (ediff-get-diff-posn 'A 'beg n))) + (> ediff-auto-refine-limit + (- (ediff-get-diff-posn 'B 'end n) + (ediff-get-diff-posn 'B 'beg n)))) + (ediff-make-fine-diffs n 'noforce) + (ediff-make-fine-diffs n 'skip))) + + ;; highlight iff fine diffs already exist + ((eq ediff-auto-refine 'off) + (ediff-make-fine-diffs n 'skip)))) + + +;; if fine diff vector is not set for diff N, then do nothing +(defun ediff-set-fine-diff-properties (n &optional default) + (or (not (ediff-has-face-support-p)) + (< n 0) + (>= n ediff-number-of-differences) + ;; when faces are supported, set faces and priorities of fine overlays + (progn + (ediff-set-fine-diff-properties-in-one-buffer 'A n default) + (ediff-set-fine-diff-properties-in-one-buffer 'B n default) + (if ediff-3way-job + (ediff-set-fine-diff-properties-in-one-buffer 'C n default))))) + +(defun ediff-set-fine-diff-properties-in-one-buffer (buf-type + n &optional default) + (let ((fine-diff-vector (ediff-get-fine-diff-vector n buf-type)) + (face (if default + 'default + (face-name + (ediff-get-symbol-from-alist + buf-type ediff-fine-diff-face-alist)))) + (priority (if default + 0 + (1+ (or (ediff-overlay-get + (symbol-value + (ediff-get-symbol-from-alist + buf-type + ediff-current-diff-overlay-alist)) + 'priority) + 0))))) + (mapcar (lambda (overl) + (ediff-set-overlay-face overl face) + (ediff-overlay-put overl 'priority priority)) + fine-diff-vector))) + +;; Set overlays over the regions that denote delimiters +(defun ediff-set-fine-overlays-for-combined-merge (diff-list reg-num) + (let (overlay overlay-list) + (while diff-list + (condition-case nil + (setq overlay + (ediff-make-bullet-proof-overlay + (nth 0 diff-list) (nth 1 diff-list) ediff-buffer-C)) + (error "")) + (setq overlay-list (cons overlay overlay-list)) + (if (> (length diff-list) 1) + (setq diff-list (cdr (cdr diff-list))) + (error "ediff-set-fine-overlays-for-combined-merge: corrupt list of +delimiter regions")) + ) + (setq overlay-list (reverse overlay-list)) + (ediff-set-fine-diff-vector + reg-num 'C (apply 'vector overlay-list)) + )) + + +;; Convert diff list to overlays for a given DIFF-REGION +;; in buffer of type BUF-TYPE +(defun ediff-set-fine-overlays-in-one-buffer (buf-type diff-list region-num) + (let* ((current-diff -1) + (reg-start (ediff-get-diff-posn buf-type 'beg region-num)) + (buff (ediff-get-buffer buf-type)) + (ctl-buf ediff-control-buffer) + combined-merge-diff-list + diff-overlay-list list-element + begin end overlay) + + (ediff-clear-fine-differences-in-one-buffer region-num buf-type) + (setq diff-list (cdr diff-list)) ; discard list type (words or points) + (ediff-with-current-buffer buff (goto-char reg-start)) + + ;; if it is a combined merge then set overlays in buff C specially + (if (and ediff-merge-job (eq buf-type 'C) + (setq combined-merge-diff-list + (ediff-looks-like-combined-merge region-num))) + (ediff-set-fine-overlays-for-combined-merge + combined-merge-diff-list region-num) + ;; regular fine diff + (while diff-list + (setq current-diff (1+ current-diff) + list-element (car diff-list) + begin (aref list-element (cond ((eq buf-type 'A) 0) + ((eq buf-type 'B) 2) + (t 4))) ; buf C + end (aref list-element (cond ((eq buf-type 'A) 1) + ((eq buf-type 'B) 3) + (t 5)))) ; buf C + (if (not (or begin end)) + () ; skip this diff + ;; Put overlays at appropriate places in buffers + ;; convert lines to points, if necessary + (ediff-with-current-buffer ctl-buf + (setq begin (ediff-goto-word (1+ begin) buff) + end (ediff-goto-word end buff 'end))) + (setq overlay (ediff-make-bullet-proof-overlay begin end buff)) + ;; record all overlays for this difference region + (setq diff-overlay-list (nconc diff-overlay-list (list overlay)))) + + (setq diff-list (cdr diff-list)) + ) ; while + ;; convert the list of difference information into a vector + ;; for fast access + (ediff-set-fine-diff-vector + region-num buf-type (vconcat diff-overlay-list)) + ))) + + +(defsubst ediff-convert-fine-diffs-to-overlays (diff-list region-num) + (ediff-set-fine-overlays-in-one-buffer 'A diff-list region-num) + (ediff-set-fine-overlays-in-one-buffer 'B diff-list region-num) + (if ediff-3way-job + (ediff-set-fine-overlays-in-one-buffer 'C diff-list region-num) + )) + + +;; Stolen from emerge.el +(defun ediff-get-diff3-group (file) + ;; This save-excursion allows ediff-get-diff3-group to be called for the + ;; various groups of lines (1, 2, 3) in any order, and for the lines to + ;; appear in any order. The reason this is necessary is that Gnu diff3 + ;; can produce the groups in the order 1, 2, 3 or 1, 3, 2. + (save-excursion + (re-search-forward + (concat "^" file ":\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\\([ac]\\)\C-m?$")) + (beginning-of-line 2) + ;; treatment depends on whether it is an "a" group or a "c" group + (if (string-equal (buffer-substring (match-beginning 4) (match-end 4)) "c") + ;; it is a "c" group + (if (match-beginning 2) + ;; it has two numbers + (list (string-to-number + (buffer-substring (match-beginning 1) (match-end 1))) + (1+ (string-to-number + (buffer-substring (match-beginning 3) (match-end 3))))) + ;; it has one number + (let ((x (string-to-number + (buffer-substring (match-beginning 1) (match-end 1))))) + (list x (1+ x)))) + ;; it is an "a" group + (let ((x (1+ (string-to-number + (buffer-substring (match-beginning 1) (match-end 1)))))) + (list x x))))) + + +;; If WORD-MODE, construct vector of diffs using word numbers. +;; Else, use point values. +;; WORD-MODE also tells if we are in the word-mode or not. +;; If THREE-WAY-COMP, then it is a 3-way comparison. Else, it is merging +;; with ancestor, in which case buffer-C contents is identical to buffer-A/B, +;; contents (unless buffer-A is narrowed) depending on ediff-default-variant's +;; value. +;; BOUNDS specifies visibility bounds to use. +(defun ediff-extract-diffs3 (diff-buffer word-mode three-way-comp + &optional bounds) + (let ((A-buffer ediff-buffer-A) + (B-buffer ediff-buffer-B) + (C-buffer ediff-buffer-C) + (anc-buffer ediff-ancestor-buffer) + (a-prev 1) ; needed to set the first diff line correctly + (a-prev-pt nil) + (b-prev 1) + (b-prev-pt nil) + (c-prev 1) + (c-prev-pt nil) + (anc-prev 1) + diff-list shift-A shift-B shift-C + ) + + ;; diff list contains word numbers or points, depending on word-mode + (setq diff-list (cons (if word-mode 'words 'points) + diff-list)) + (if bounds + (setq shift-A + (ediff-overlay-start + (ediff-get-value-according-to-buffer-type 'A bounds)) + shift-B + (ediff-overlay-start + (ediff-get-value-according-to-buffer-type 'B bounds)) + shift-C + (if three-way-comp + (ediff-overlay-start + (ediff-get-value-according-to-buffer-type 'C bounds))))) + + ;; reset point in buffers A, B, C + (ediff-with-current-buffer A-buffer + (goto-char (if shift-A shift-A (point-min)))) + (ediff-with-current-buffer B-buffer + (goto-char (if shift-B shift-B (point-min)))) + (if three-way-comp + (ediff-with-current-buffer C-buffer + (goto-char (if shift-C shift-C (point-min))))) + (if (ediff-buffer-live-p anc-buffer) + (ediff-with-current-buffer anc-buffer + (goto-char (point-min)))) + + (ediff-with-current-buffer diff-buffer + (goto-char (point-min)) + (while (re-search-forward ediff-match-diff3-line nil t) + ;; leave point after matched line + (beginning-of-line 2) + (let ((agreement (buffer-substring (match-beginning 1) (match-end 1)))) + ;; if the files A and B are the same and not 3way-comparison, + ;; ignore the difference + (if (or three-way-comp (not (string-equal agreement "3"))) + (let* ((a-begin (car (ediff-get-diff3-group "1"))) + (a-end (nth 1 (ediff-get-diff3-group "1"))) + (b-begin (car (ediff-get-diff3-group "2"))) + (b-end (nth 1 (ediff-get-diff3-group "2"))) + (c-or-anc-begin (car (ediff-get-diff3-group "3"))) + (c-or-anc-end (nth 1 (ediff-get-diff3-group "3"))) + (state-of-merge + (cond ((string-equal agreement "1") 'prefer-A) + ((string-equal agreement "2") 'prefer-B) + (t ediff-default-variant))) + (state-of-diff-merge + (if (memq state-of-merge '(default-A prefer-A)) 'B 'A)) + (state-of-diff-comparison + (cond ((string-equal agreement "1") 'A) + ((string-equal agreement "2") 'B) + ((string-equal agreement "3") 'C))) + state-of-ancestor + c-begin c-end + a-begin-pt a-end-pt + b-begin-pt b-end-pt + c-begin-pt c-end-pt + anc-begin-pt anc-end-pt) + + (setq state-of-ancestor + (= c-or-anc-begin c-or-anc-end)) + + (cond (three-way-comp + (setq c-begin c-or-anc-begin + c-end c-or-anc-end)) + ((eq ediff-default-variant 'default-B) + (setq c-begin b-begin + c-end b-end)) + (t + (setq c-begin a-begin + c-end a-end))) + + ;; compute main diff vector + (if word-mode + ;; make diff-list contain word numbers + (setq diff-list + (nconc diff-list + (list (vector + (- a-begin a-prev) (- a-end a-begin) + (- b-begin b-prev) (- b-end b-begin) + (- c-begin c-prev) (- c-end c-begin) + nil nil ; dummy ancestor + nil ; state of diff + nil ; state of merge + nil ; state of ancestor + ))) + a-prev a-end + b-prev b-end + c-prev c-end) + ;; else convert lines to points + (ediff-with-current-buffer A-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + ;; we must disable and then restore longlines-mode + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or a-prev-pt shift-A (point-min))) + (forward-line (- a-begin a-prev)) + (setq a-begin-pt (point)) + (forward-line (- a-end a-begin)) + (setq a-end-pt (point) + a-prev a-end + a-prev-pt a-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + )) + (ediff-with-current-buffer B-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or b-prev-pt shift-B (point-min))) + (forward-line (- b-begin b-prev)) + (setq b-begin-pt (point)) + (forward-line (- b-end b-begin)) + (setq b-end-pt (point) + b-prev b-end + b-prev-pt b-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + )) + (ediff-with-current-buffer C-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (goto-char (or c-prev-pt shift-C (point-min))) + (forward-line (- c-begin c-prev)) + (setq c-begin-pt (point)) + (forward-line (- c-end c-begin)) + (setq c-end-pt (point) + c-prev c-end + c-prev-pt c-end-pt) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + )) + (if (ediff-buffer-live-p anc-buffer) + (ediff-with-current-buffer anc-buffer + (let ((longlines-mode-val + (if (and (boundp 'longlines-mode) longlines-mode) 1 0))) + (if (eq longlines-mode-val 1) + (longlines-mode 0)) + (forward-line (- c-or-anc-begin anc-prev)) + (setq anc-begin-pt (point)) + (forward-line (- c-or-anc-end c-or-anc-begin)) + (setq anc-end-pt (point) + anc-prev c-or-anc-end) + (if (eq longlines-mode-val 1) + (longlines-mode longlines-mode-val)) + ))) + (setq diff-list + (nconc + diff-list + ;; if comparing with ancestor, then there also is a + ;; state-of-difference marker + (if three-way-comp + (list (vector + a-begin-pt a-end-pt + b-begin-pt b-end-pt + c-begin-pt c-end-pt + nil nil ; ancestor begin/end + state-of-diff-comparison + nil ; state of merge + nil ; state of ancestor + )) + (list (vector a-begin-pt a-end-pt + b-begin-pt b-end-pt + c-begin-pt c-end-pt + anc-begin-pt anc-end-pt + state-of-diff-merge + state-of-merge + state-of-ancestor + ))) + ))) + )) + + ))) ; end ediff-with-current-buffer + diff-list + )) + +;; Generate the difference vector and overlays for three files +;; File-C is either the third file to compare (in case of 3-way comparison) +;; or it is the ancestor file. +(defun ediff-setup-diff-regions3 (file-A file-B file-C) + ;; looking for '-i' or a 'i' among clustered non-long options + (if (string-match "^-i\\| -i\\|\\(^\\| \\)-[^- ]+i" ediff-diff-options) + (error "Option `-i' is not allowed in `ediff-diff3-options'")) + + (or (ediff-buffer-live-p ediff-diff-buffer) + (setq ediff-diff-buffer + (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*")))) + + (message "Computing differences ...") + (ediff-exec-process ediff-diff3-program ediff-diff-buffer 'synchronize + ediff-actual-diff3-options file-A file-B file-C) + + (ediff-prepare-error-list ediff-diff3-ok-lines-regexp ediff-diff-buffer) + ;;(message "Computing differences ... done") + (ediff-convert-diffs-to-overlays + (ediff-extract-diffs3 + ediff-diff-buffer + ediff-word-mode ediff-3way-comparison-job ediff-narrow-bounds) + )) + + +;; Execute PROGRAM asynchronously, unless OS/2, Windows-*, or DOS, or unless +;; SYNCH is non-nil. BUFFER must be a buffer object, and must be alive. The +;; OPTIONS arg is a list of options to pass to PROGRAM. It may be a blank +;; string. All elements in FILES must be strings. We also delete nil from +;; args. +(defun ediff-exec-process (program buffer synch options &rest files) + (let ((data (match-data)) + (coding-system-for-read ediff-coding-system-for-read) + args) + (setq args (append (split-string options) files)) + (setq args (delete "" (delq nil args))) ; delete nil and "" from arguments + ;; the --binary option, if present, should be used only for buffer jobs + ;; or for refining the differences + (or (string-match "buffer" (symbol-name ediff-job-name)) + (eq buffer ediff-fine-diff-buffer) + (setq args (delete "--binary" args))) + (unwind-protect + (let ((directory default-directory) + proc) + (save-excursion + (set-buffer buffer) + (erase-buffer) + (setq default-directory directory) + (if (or (memq system-type '(emx ms-dos windows-nt windows-95)) + synch) + ;; In OS/2 (emx) do it synchronously, since OS/2 doesn't let us + ;; delete files used by other processes. Thus, in ediff-buffers + ;; and similar functions, we can't delete temp files because + ;; they might be used by the asynch process that computes + ;; custom diffs. So, we have to wait till custom diff + ;; subprocess is done. + ;; Similarly for Windows-* + ;; In DOS, must synchronize because DOS doesn't have + ;; asynchronous processes. + (apply 'call-process program nil buffer nil args) + ;; On other systems, do it asynchronously. + (setq proc (get-buffer-process buffer)) + (if proc (kill-process proc)) + (setq proc + (apply 'start-process "Custom Diff" buffer program args)) + (setq mode-line-process '(":%s")) + (set-process-sentinel proc 'ediff-process-sentinel) + (set-process-filter proc 'ediff-process-filter) + ))) + (store-match-data data)))) + +;; This is shell-command-filter from simple.el in Emacs. +;; Copied here because XEmacs doesn't have it. +(defun ediff-process-filter (proc string) + ;; Do save-excursion by hand so that we can leave point numerically unchanged + ;; despite an insertion immediately after it. + (let* ((obuf (current-buffer)) + (buffer (process-buffer proc)) + opoint + (window (get-buffer-window buffer)) + (pos (window-start window))) + (unwind-protect + (progn + (set-buffer buffer) + (or (= (point) (point-max)) + (setq opoint (point))) + (goto-char (point-max)) + (insert-before-markers string)) + ;; insert-before-markers moved this marker: set it back. + (set-window-start window pos) + ;; Finish our save-excursion. + (if opoint + (goto-char opoint)) + (set-buffer obuf)))) + +;; like shell-command-sentinel but doesn't print an exit status message +;; we do this because diff always exits with status 1, if diffs are found +;; so shell-command-sentinel displays a confusing message to the user +(defun ediff-process-sentinel (process signal) + (if (and (memq (process-status process) '(exit signal)) + (buffer-name (process-buffer process))) + (progn + (save-excursion + (set-buffer (process-buffer process)) + (setq mode-line-process nil)) + (delete-process process)))) + + +;;; Word functions used to refine the current diff + +(defvar ediff-forward-word-function 'ediff-forward-word + "*Function to call to move to the next word. +Used for splitting difference regions into individual words.") +(make-variable-buffer-local 'ediff-forward-word-function) + +(defvar ediff-whitespace " \n\t\f" + "*Characters constituting white space. +These characters are ignored when differing regions are split into words.") +(make-variable-buffer-local 'ediff-whitespace) + +(defvar ediff-word-1 + (ediff-cond-compile-for-xemacs-or-emacs "a-zA-Z---_" "-[:word:]_") + "*Characters that constitute words of type 1. +More precisely, [ediff-word-1] is a regexp that matches type 1 words. +See `ediff-forward-word' for more details.") +(make-variable-buffer-local 'ediff-word-1) + +(defvar ediff-word-2 "0-9.," + "*Characters that constitute words of type 2. +More precisely, [ediff-word-2] is a regexp that matches type 2 words. +See `ediff-forward-word' for more details.") +(make-variable-buffer-local 'ediff-word-2) + +(defvar ediff-word-3 "`'?!:;\"{}[]()" + "*Characters that constitute words of type 3. +More precisely, [ediff-word-3] is a regexp that matches type 3 words. +See `ediff-forward-word' for more details.") +(make-variable-buffer-local 'ediff-word-3) + +(defvar ediff-word-4 + (concat "^" ediff-word-1 ediff-word-2 ediff-word-3 ediff-whitespace) + "*Characters that constitute words of type 4. +More precisely, [ediff-word-4] is a regexp that matches type 4 words. +See `ediff-forward-word' for more details.") +(make-variable-buffer-local 'ediff-word-4) + +;; Split region along word boundaries. Each word will be on its own line. +;; Output to buffer out-buffer. +(defun ediff-forward-word () + "Move point one word forward. +There are four types of words, each of which consists entirely of +characters in `ediff-word-1', `ediff-word-2', `ediff-word-3', or +`ediff-word-4'. Words are recognized by passing these one after another as +arguments to `skip-chars-forward'." + (or (> (+ (skip-chars-forward ediff-word-1) + (skip-syntax-forward "w")) + 0) + (> (skip-chars-forward ediff-word-2) 0) + (> (skip-chars-forward ediff-word-3) 0) + (> (skip-chars-forward ediff-word-4) 0) + )) + + +(defun ediff-wordify (beg end in-buffer out-buffer &optional control-buf) + (let ((forward-word-function + ;; eval in control buf to let user create local versions for + ;; different invocations + (if control-buf + (ediff-with-current-buffer control-buf + ediff-forward-word-function) + ediff-forward-word-function)) + inbuf-syntax-tbl sv-point diff-string) + (save-excursion + (set-buffer in-buffer) + (setq inbuf-syntax-tbl + (if control-buf + (ediff-with-current-buffer control-buf + ediff-syntax-table) + (syntax-table))) + (setq diff-string (buffer-substring-no-properties beg end)) + + (set-buffer out-buffer) + ;; Make sure that temp buff syntax table is the same as the original buf + ;; syntax tbl, because we use ediff-forward-word in both and + ;; ediff-forward-word depends on the syntax classes of characters. + (set-syntax-table inbuf-syntax-tbl) + (erase-buffer) + (insert diff-string) + (goto-char (point-min)) + (skip-chars-forward ediff-whitespace) + (delete-region (point-min) (point)) + + (while (not (eobp)) + (funcall forward-word-function) + (setq sv-point (point)) + (skip-chars-forward ediff-whitespace) + (delete-region sv-point (point)) + (insert "\n"))))) + +;; copy string specified as BEG END from IN-BUF to OUT-BUF +(defun ediff-copy-to-buffer (beg end in-buffer out-buffer) + (with-current-buffer out-buffer + (erase-buffer) + (insert-buffer-substring in-buffer beg end) + (goto-char (point-min)))) + + +;; goto word #n starting at current position in buffer `buf' +;; For ediff, a word is determined by ediff-forward-word-function +;; If `flag' is non-nil, goto the end of the n-th word. +(defun ediff-goto-word (n buf &optional flag) + ;; remember val ediff-forward-word-function has in ctl buf + (let ((fwd-word-fun ediff-forward-word-function) + (syntax-tbl ediff-syntax-table)) + (ediff-with-current-buffer buf + (skip-chars-forward ediff-whitespace) + (ediff-with-syntax-table syntax-tbl + (while (> n 1) + (funcall fwd-word-fun) + (skip-chars-forward ediff-whitespace) + (setq n (1- n))) + (if (and flag (> n 0)) + (funcall fwd-word-fun))) + (point)))) + +(defun ediff-same-file-contents (f1 f2) + "Return t if files F1 and F2 have identical contents." + (if (and (not (file-directory-p f1)) + (not (file-directory-p f2))) + (let ((res + (apply 'call-process ediff-cmp-program nil nil nil + (append ediff-cmp-options (list f1 f2))))) + (and (numberp res) (eq res 0)))) + ) + + +(defun ediff-same-contents (d1 d2 &optional filter-re) + "Returns t iff D1 and D2 have the same content. +D1 and D2 can either be both directories or both regular files. +Symlinks and the likes are not handled. +If FILTER-RE is non-nil, recursive checking in directories +affects only files whose names match the expression." + ;; Normalize empty filter RE to nil. + (unless (> (length filter-re) 0) (setq filter-re nil)) + ;; Indicate progress + (message "Comparing '%s' and '%s' modulo '%s'" d1 d2 filter-re) + (cond + ;; D1 & D2 directories => recurse + ((and (file-directory-p d1) + (file-directory-p d2)) + (if (null ediff-recurse-to-subdirectories) + (if (y-or-n-p "Compare subdirectories recursively? ") + (setq ediff-recurse-to-subdirectories 'yes) + (setq ediff-recurse-to-subdirectories 'no))) + (if (eq ediff-recurse-to-subdirectories 'yes) + (let* ((all-entries-1 (directory-files d1 t filter-re)) + (all-entries-2 (directory-files d2 t filter-re)) + (entries-1 (ediff-delete-all-matches "^\\.\\.?$" all-entries-1)) + (entries-2 (ediff-delete-all-matches "^\\.\\.?$" all-entries-2)) + ) + + (ediff-same-file-contents-lists entries-1 entries-2 filter-re) + )) + ) ; end of the directories case + ;; D1 & D2 are both files => compare directly + ((and (file-regular-p d1) + (file-regular-p d2)) + (ediff-same-file-contents d1 d2)) + ;; Otherwise => false: unequal contents + ) + ) + +;; If lists have the same length and names of files are pairwise equal +;; (removing the directories) then compare contents pairwise. +;; True if all contents are the same; false otherwise +(defun ediff-same-file-contents-lists (entries-1 entries-2 filter-re) + ;; First, check only the names (works quickly and ensures a + ;; precondition for subsequent code) + (if (and (= (length entries-1) (length entries-2)) + (equal (mapcar 'file-name-nondirectory entries-1) + (mapcar 'file-name-nondirectory entries-2))) + ;; With name equality established, compare the entries + ;; through recursion. + (let ((continue t)) + (while (and entries-1 continue) + (if (ediff-same-contents + (car entries-1) (car entries-2) filter-re) + (setq entries-1 (cdr entries-1) + entries-2 (cdr entries-2)) + (setq continue nil)) + ) + ;; if reached the end then lists are equal + (null entries-1)) + ) + ) + + +;; ARG1 is a regexp, ARG2 is a list of full-filenames +;; Delete all entries that match the regexp +(defun ediff-delete-all-matches (regex file-list-list) + (let (result elt) + (while file-list-list + (setq elt (car file-list-list)) + (or (string-match regex (file-name-nondirectory elt)) + (setq result (cons elt result))) + (setq file-list-list (cdr file-list-list))) + (reverse result))) + +;; Ignore case handling - some ideas from drew.adams@@oracle.com +(defun ediff-toggle-ignore-case () + (interactive) + (ediff-barf-if-not-control-buffer) + (setq ediff-ignore-case (not ediff-ignore-case)) + (cond (ediff-ignore-case + (setq ediff-actual-diff-options + (concat ediff-diff-options " " ediff-ignore-case-option) + ediff-actual-diff3-options + (concat ediff-diff3-options " " ediff-ignore-case-option3)) + (message "Ignoring regions that differ only in case")) + (t + (setq ediff-actual-diff-options ediff-diff-options + ediff-actual-diff3-options ediff-diff3-options) + (message "Ignoring case differences turned OFF"))) + (cond (ediff-merge-job + (message "Ignoring letter case is too dangerous in merge jobs")) + ((and ediff-diff3-job (string= ediff-ignore-case-option3 "")) + (message "Ignoring letter case is not supported by this diff3 program")) + ((and (not ediff-3way-job) (string= ediff-ignore-case-option "")) + (message "Ignoring letter case is not supported by this diff program")) + (t + (sit-for 1) + (ediff-update-diffs))) + ) + + +(provide 'ediff-diff) + + +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) +;;; End: + +;;; arch-tag: a86d448e-58d7-4572-a1d9-fdedfa22f648 +;;; ediff-diff.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-diff.elc b/xemacs-packages/lisp/ediff/ediff-diff.elc new file mode 100644 index 0000000000000000000000000000000000000000..a8157b479d484d54d5294e5d8449dc39e70d443d GIT binary patch literal 29203 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 literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/ediff-help.el b/xemacs-packages/lisp/ediff/ediff-help.el new file mode 100644 index 00000000..d5f505c7 --- /dev/null +++ b/xemacs-packages/lisp/ediff/ediff-help.el @@ -0,0 +1,332 @@ +;;; ediff-help.el --- Code related to the contents of Ediff help buffers + +;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +;; 2004, 2005, 2006 Free Software Foundation, Inc. + +;; Author: Michael Kifer + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;;; Code: + + +;; Compiler pacifier start +(defvar ediff-multiframe) + +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + )) +;; end pacifier + +(require 'ediff-init) + +;; Help messages + +(defconst ediff-long-help-message-head + " Move around | Toggle features | Manipulate +=====================|===========================|=============================" + "The head of the full help message.") +(defconst ediff-long-help-message-tail + "=====================|===========================|============================= + R -show registry | = -compare regions | M -show session group + D -diff output | E -browse Ediff manual| G -send bug report + i -status info | ? -help off | z/q -suspend/quit +------------------------------------------------------------------------------- +For help on a specific command: Click Button 2 over it; or + Put the cursor over it and type RET." + "The tail of the full-help message.") + +(defconst ediff-long-help-message-compare3 + " +p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y +n,SPC -next diff | h -hilighting | rx -restore buf X's old diff + j -jump to diff | @ -auto-refinement | * -refine current region + gx -goto X's point| ## -ignore whitespace | ! -update diff regions + C-l -recenter | #c -ignore case | + v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X + -scroll lt/rt | X -read-only in buf X | wd -save diff output + ~ -rotate buffers| m -wide display | +" + "Help message usually used for 3-way comparison. +Normally, not a user option. See `ediff-help-message' for details.") + +(defconst ediff-long-help-message-compare2 + " +p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A +n,SPC -next diff | h -hilighting | rx -restore buf X's old diff + j -jump to diff | @ -auto-refinement | * -refine current region + gx -goto X's point| ## -ignore whitespace | ! -update diff regions + C-l -recenter | #c -ignore case | + v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X + -scroll lt/rt | X -read-only in buf X | wd -save diff output + ~ -swap variants | m -wide display | +" + "Help message usually used for 2-way comparison. +Normally, not a user option. See `ediff-help-message' for details.") + +(defconst ediff-long-help-message-narrow2 + " +p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A +n,SPC -next diff | h -hilighting | rx -restore buf X's old diff + j -jump to diff | @ -auto-refinement | * -refine current region + gx -goto X's point| ## -ignore whitespace | ! -update diff regions + C-l -recenter | #c -ignore case | % -narrow/widen buffs + v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X + -scroll lt/rt | X -read-only in buf X | wd -save diff output + ~ -swap variants | m -wide display | +" + "Help message when comparing windows or regions line-by-line. +Normally, not a user option. See `ediff-help-message' for details.") + +(defconst ediff-long-help-message-word-mode + " +p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y +n,SPC -next diff | h -hilighting | rx -restore buf X's old diff + j -jump to diff | | + gx -goto X's point| % -narrow/widen buffs | ! -recompute diffs + C-l -recenter | #c -ignore case | + v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X + -scroll lt/rt | X -read-only in buf X | wd -save diff output + ~ -swap variants | m -wide display | +" + "Help message when comparing windows or regions word-by-word. +Normally, not a user option. See `ediff-help-message' for details.") + +(defconst ediff-long-help-message-merge + " +p,DEL -previous diff | | -vert/horiz split | x -copy buf X's region to C +n,SPC -next diff | h -hilighting | r -restore buf C's old diff + j -jump to diff | @ -auto-refinement | * -refine current region + gx -goto X's point| ## -ignore whitespace | ! -update diff regions + C-l -recenter | #f/#h -focus/hide regions | + -combine diff regions + v/V -scroll up/dn | X -read-only in buf X | wx -save buf X + -scroll lt/rt | m -wide display | wd -save diff output + ~ -swap variants | s -shrink window C | / -show ancestor buff + | $$ -show clashes only | & -merge w/new default + | $* -skip changed regions | +" + "Help message for merge sessions. +Normally, not a user option. See `ediff-help-message' for details.") + +;; The actual long help message. +(ediff-defvar-local ediff-long-help-message "" + "Normally, not a user option. See `ediff-help-message' for details.") + +(defconst ediff-brief-message-string + " Type ? for help" + "Contents of the brief help message.") +;; The actual brief help message +(ediff-defvar-local ediff-brief-help-message "" + "Normally, not a user option. See `ediff-help-message' for details.") + +(ediff-defvar-local ediff-brief-help-message-function nil + "The brief help message that the user can customize. +If the user sets this to a parameter-less function, Ediff will use it to +produce the brief help message. This function must return a string.") +(ediff-defvar-local ediff-long-help-message-function nil + "The long help message that the user can customize. +See `ediff-brief-help-message-function' for more.") + +(defcustom ediff-use-long-help-message nil + "*If t, Ediff displays a long help message. Short help message otherwise." + :type 'boolean + :group 'ediff-window) + +;; The actual help message. +(ediff-defvar-local ediff-help-message "" + "The actual help message. +Normally, the user shouldn't touch this. However, if you want Ediff to +start up with different help messages for different jobs, you can change +the value of this variable and the variables `ediff-help-message-*' in +`ediff-startup-hook'.") + + +;; the keymap that defines clicks over the quick help regions +(defvar ediff-help-region-map (make-sparse-keymap)) + +(define-key + ediff-help-region-map + (if ediff-emacs-p [mouse-2] [button2]) + 'ediff-help-for-quick-help) + +;; runs in the control buffer +(defun ediff-set-help-overlays () + (goto-char (point-min)) + (let (overl beg end cmd) + (while (re-search-forward " *\\([^ \t\n|]+\\||\\) +-[^|\n]+" nil 'noerror) + (setq beg (match-beginning 0) + end (match-end 0) + cmd (buffer-substring (match-beginning 1) (match-end 1))) + (setq overl (ediff-make-overlay beg end)) + (if ediff-emacs-p + (ediff-overlay-put overl 'mouse-face 'highlight) + (ediff-overlay-put overl 'highlight t)) + (ediff-overlay-put overl 'ediff-help-info cmd)))) + + +(defun ediff-help-for-quick-help () + "Explain Ediff commands in more detail." + (interactive) + (ediff-barf-if-not-control-buffer) + (let ((pos (ediff-event-point last-command-event)) + overl cmd) + + (ediff-cond-compile-for-xemacs-or-emacs + ;; xemacs + (setq overl (extent-at pos (current-buffer) 'ediff-help-info) + cmd (ediff-overlay-get overl 'ediff-help-info)) + ;; emacs + (setq cmd (car (mapcar (lambda (elt) + (overlay-get elt 'ediff-help-info)) + (overlays-at pos)))) + ) + + (if (not (stringp cmd)) + (error "Hmm... I don't see an Ediff command around here...")) + + (ediff-documentation "Quick Help Commands") + + (let (case-fold-search) + (cond ((string= cmd "?") (re-search-forward "^`\\?'")) + ((string= cmd "G") (re-search-forward "^`G'")) + ((string= cmd "E") (re-search-forward "^`E'")) + ((string= cmd "wd") (re-search-forward "^`wd'")) + ((string= cmd "wx") (re-search-forward "^`wa'")) + ((string= cmd "a/b") (re-search-forward "^`a'")) + ((string= cmd "x") (re-search-forward "^`a'")) + ((string= cmd "xy") (re-search-forward "^`ab'")) + ((string= cmd "p,DEL") (re-search-forward "^`p'")) + ((string= cmd "n,SPC") (re-search-forward "^`n'")) + ((string= cmd "j") (re-search-forward "^`j'")) + ((string= cmd "gx") (re-search-forward "^`ga'")) + ((string= cmd "!") (re-search-forward "^`!'")) + ((string= cmd "*") (re-search-forward "^`\\*'")) + ((string= cmd "m") (re-search-forward "^`m'")) + ((string= cmd "|") (re-search-forward "^`|'")) + ((string= cmd "@") (re-search-forward "^`@'")) + ((string= cmd "h") (re-search-forward "^`h'")) + ((string= cmd "r") (re-search-forward "^`r'")) + ((string= cmd "rx") (re-search-forward "^`ra'")) + ((string= cmd "##") (re-search-forward "^`##'")) + ((string= cmd "#c") (re-search-forward "^`#c'")) + ((string= cmd "#f/#h") (re-search-forward "^`#f'")) + ((string= cmd "X") (re-search-forward "^`A'")) + ((string= cmd "v/V") (re-search-forward "^`v'")) + ((string= cmd "") (re-search-forward "^`<'")) + ((string= cmd "~") (re-search-forward "^`~'")) + ((string= cmd "i") (re-search-forward "^`i'")) + ((string= cmd "D") (re-search-forward "^`D'")) + ((string= cmd "R") (re-search-forward "^`R'")) + ((string= cmd "M") (re-search-forward "^`M'")) + ((string= cmd "z/q") (re-search-forward "^`z'")) + ((string= cmd "%") (re-search-forward "^`%'")) + ((string= cmd "C-l") (re-search-forward "^`C-l'")) + ((string= cmd "$$") (re-search-forward "^`\\$\\$'")) + ((string= cmd "$*") (re-search-forward "^`\\$\\*'")) + ((string= cmd "/") (re-search-forward "^`/'")) + ((string= cmd "&") (re-search-forward "^`&'")) + ((string= cmd "s") (re-search-forward "^`s'")) + ((string= cmd "+") (re-search-forward "^`\\+'")) + ((string= cmd "=") (re-search-forward "^`='")) + (t (error "Undocumented command! Type `G' in Ediff Control Panel to drop a note to the Ediff maintainer"))) + ) ; let case-fold-search + )) + + +;; assuming we are in control window, calculate length of the first line in +;; help message +(defun ediff-help-message-line-length () + (save-excursion + (goto-char (point-min)) + (if ediff-use-long-help-message + (next-line 1)) + (end-of-line) + (current-column))) + + +(defun ediff-indent-help-message () + (let* ((shift (/ (max 0 (- (window-width (selected-window)) + (ediff-help-message-line-length))) + 2)) + (str (make-string shift ?\ ))) + (save-excursion + (goto-char (point-min)) + (while (< (point) (point-max)) + (insert str) + (beginning-of-line) + (forward-line 1))))) + + +;; compose the help message as a string +(defun ediff-set-help-message () + (setq ediff-long-help-message + (cond ((and ediff-long-help-message-function + (or (symbolp ediff-long-help-message-function) + (consp ediff-long-help-message-function))) + (funcall ediff-long-help-message-function)) + (ediff-word-mode + (concat ediff-long-help-message-head + ediff-long-help-message-word-mode + ediff-long-help-message-tail)) + (ediff-narrow-job + (concat ediff-long-help-message-head + ediff-long-help-message-narrow2 + ediff-long-help-message-tail)) + (ediff-merge-job + (concat ediff-long-help-message-head + ediff-long-help-message-merge + ediff-long-help-message-tail)) + (ediff-diff3-job + (concat ediff-long-help-message-head + ediff-long-help-message-compare3 + ediff-long-help-message-tail)) + (t + (concat ediff-long-help-message-head + ediff-long-help-message-compare2 + ediff-long-help-message-tail)))) + (setq ediff-brief-help-message + (cond ((and ediff-brief-help-message-function + (or (symbolp ediff-brief-help-message-function) + (consp ediff-brief-help-message-function))) + (funcall ediff-brief-help-message-function)) + ((stringp ediff-brief-help-message-function) + ediff-brief-help-message-function) + ((ediff-multiframe-setup-p) ediff-brief-message-string) + (t ; long brief msg, not multiframe --- put in the middle + ediff-brief-message-string) + )) + (setq ediff-help-message (if ediff-use-long-help-message + ediff-long-help-message + ediff-brief-help-message)) + (run-hooks 'ediff-display-help-hook)) + +;;;###autoload +(defun ediff-customize () + (interactive) + (customize-group "ediff")) + + +(provide 'ediff-help) + + +;;; arch-tag: 05659813-7fcf-4274-964f-d2f577431a9d +;;; ediff-help.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-help.elc b/xemacs-packages/lisp/ediff/ediff-help.elc new file mode 100644 index 0000000000000000000000000000000000000000..ced107d04cd4e5b17e36a30c996d39b247de7e14 GIT binary patch literal 10363 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

Ltd*tjy zen~=H3F&>rB}6Wb83^Wx&m7$2M<|hmxCBQgXTC;7`xko}`uIJITOZfD8=#FAa{&JQcIP&7*e4@<(?B}1KC_%5R!tU;$xRA z+7TshDVIAtaX8(Ix<8*-Au4A$3L88wE=S|ww9z>pGmi=k7n0P^3z9oH#3@W*NNFfc zQgTCbzSy#Fe>S_J4b5Bef8YMCOb!b<%w#PubS*E;A;p-?pwb|mFx+qmKa+q2Gsmq` zp%cEstkl%Mo2!mXxI!OBgO=DZaq`o+NSo3-Q;@>sZXw+Qe3ZV_?|lRJgn$>cU6w=s#rvM~2EbAymKFbQBw7<@CkVuf(o>@bcDW%XUnCs&zS&Eg(PM+REhHL4LIL9ZX&Z@{#4OmoM9KSIyJHM>ZaB!rypvXda$+W>Z{J2P0a3wx*o-= z)3<#U>*ih}7I;2;Ygwp+{9I+BM*01YYFy;9rZ+?F41QE11!J5Oi1U(Qhq^=DA~wRA zw|+iXbS#le27=x%G{ISXU-eMc7Xvp4En<$Qbb%(L+Xcj0w7-J6lz2|qdKT>spXVRq z^ei~M?l3bxP&22%P=kJBejilB*E`n&<~####C8lEi%n|gxuI@@Ns)+ + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;;; Code: + +;;; These must be placed in menu-bar.el in Emacs +;; +;; (define-key menu-bar-tools-menu [ediff-misc] +;; '("Ediff Miscellanea" . menu-bar-ediff-misc-menu)) +;; (define-key menu-bar-tools-menu [epatch] +;; '("Apply Patch" . menu-bar-epatch-menu)) +;; (define-key menu-bar-tools-menu [ediff-merge] +;; '("Merge" . menu-bar-ediff-merge-menu)) +;; (define-key menu-bar-tools-menu [ediff] +;; '("Compare" . menu-bar-ediff-menu)) + +;; Compiler pacifier +(defvar ediff-menu) +(defvar ediff-merge-menu) +(defvar epatch-menu) +(defvar ediff-misc-menu) +;; end pacifier + +;; allow menus to be set up without ediff-wind.el being loaded +;;;###autoload +(defvar ediff-window-setup-function) + +;; This macro is used to avoid compilation warnings. +;; The macro will expand into the form that is appropriate to the +;; compiler at hand (emacs or xemacs). +;; The autoload, below, is useless in Emacs because ediff-hook.el +;; is dumped with emacs, but it is needed in XEmacs +;;;###autoload (defmacro ediff-cond-compile-for-xemacs-or-emacs (xemacs-form emacs-form) (if (string-match "XEmacs" emacs-version) xemacs-form emacs-form)) + +(defmacro ediff-cond-compile-for-xemacs-or-emacs (xemacs-form emacs-form) + (if (string-match "XEmacs" emacs-version) + xemacs-form emacs-form)) + +;; This autoload is useless in Emacs because ediff-hook.el is dumped with +;; emacs, but it is needed in XEmacs +;;;###autoload +(ediff-cond-compile-for-xemacs-or-emacs + ;; xemacs form + (defun ediff-xemacs-init-menus () + (if (featurep 'menubar) + (progn + (add-submenu + '("Tools") ediff-menu "OO-Browser...") + (add-submenu + '("Tools") ediff-merge-menu "OO-Browser...") + (add-submenu + '("Tools") epatch-menu "OO-Browser...") + (add-submenu + '("Tools") ediff-misc-menu "OO-Browser...") + (add-menu-button + '("Tools") "-------" "OO-Browser...") + ))) + nil ; emacs form + ) + + +;; This autoload is useless in Emacs because ediff-hook.el is dumped with +;; emacs, but it is needed in XEmacs +;;;###autoload +(ediff-cond-compile-for-xemacs-or-emacs + (progn + (defvar ediff-menu + '("Compare" + ["Two Files..." ediff-files t] + ["Two Buffers..." ediff-buffers t] + ["Three Files..." ediff-files3 t] + ["Three Buffers..." ediff-buffers3 t] + "---" + ["Two Directories..." ediff-directories t] + ["Three Directories..." ediff-directories3 t] + "---" + ["File with Revision..." ediff-revision t] + ["Directory Revisions..." ediff-directory-revisions t] + "---" + ["Windows Word-by-word..." ediff-windows-wordwise t] + ["Windows Line-by-line..." ediff-windows-linewise t] + "---" + ["Regions Word-by-word..." ediff-regions-wordwise t] + ["Regions Line-by-line..." ediff-regions-linewise t] + )) + (defvar ediff-merge-menu + '("Merge" + ["Files..." ediff-merge-files t] + ["Files with Ancestor..." ediff-merge-files-with-ancestor t] + ["Buffers..." ediff-merge-buffers t] + ["Buffers with Ancestor..." + ediff-merge-buffers-with-ancestor t] + "---" + ["Directories..." ediff-merge-directories t] + ["Directories with Ancestor..." + ediff-merge-directories-with-ancestor t] + "---" + ["Revisions..." ediff-merge-revisions t] + ["Revisions with Ancestor..." + ediff-merge-revisions-with-ancestor t] + ["Directory Revisions..." ediff-merge-directory-revisions t] + ["Directory Revisions with Ancestor..." + ediff-merge-directory-revisions-with-ancestor t] + )) + (defvar epatch-menu + '("Apply Patch" + ["To a file..." ediff-patch-file t] + ["To a buffer..." ediff-patch-buffer t] + )) + (defvar ediff-misc-menu + '("Ediff Miscellanea" + ["Ediff Manual" ediff-documentation t] + ["Customize Ediff" ediff-customize t] + ["List Ediff Sessions" ediff-show-registry t] + ["Use separate frame for Ediff control buffer" + ediff-toggle-multiframe + :style toggle + :selected (if (and (featurep 'ediff-util) + (boundp 'ediff-window-setup-function)) + (eq ediff-window-setup-function + 'ediff-setup-windows-multiframe))] + ["Use a toolbar with Ediff control buffer" + ediff-toggle-use-toolbar + :style toggle + :selected (if (featurep 'ediff-tbar) + (ediff-use-toolbar-p))] + )) + + ;; put these menus before Object-Oriented-Browser in Tools menu + (if (and (featurep 'menubar) (not (featurep 'infodock)) + (not (featurep 'ediff-hook))) + (ediff-xemacs-init-menus))) + + ;; Emacs--only if menu-bar is loaded + (if (featurep 'menu-bar) + (progn + ;; initialize menu bar keymaps + (defvar menu-bar-ediff-misc-menu + (make-sparse-keymap "Ediff Miscellanea")) + (fset 'menu-bar-ediff-misc-menu + (symbol-value 'menu-bar-ediff-misc-menu)) + (defvar menu-bar-epatch-menu (make-sparse-keymap "Apply Patch")) + (fset 'menu-bar-epatch-menu (symbol-value 'menu-bar-epatch-menu)) + (defvar menu-bar-ediff-merge-menu (make-sparse-keymap "Merge")) + (fset 'menu-bar-ediff-merge-menu + (symbol-value 'menu-bar-ediff-merge-menu)) + (defvar menu-bar-ediff-menu (make-sparse-keymap "Compare")) + (fset 'menu-bar-ediff-menu (symbol-value 'menu-bar-ediff-menu)) + + ;; define ediff-menu + (define-key menu-bar-ediff-menu [window] + '("This Window and Next Window" . compare-windows)) + (define-key menu-bar-ediff-menu [ediff-windows-linewise] + '("Windows Line-by-line..." . ediff-windows-linewise)) + (define-key menu-bar-ediff-menu [ediff-windows-wordwise] + '("Windows Word-by-word..." . ediff-windows-wordwise)) + (define-key menu-bar-ediff-menu [separator-ediff-windows] '("--")) + (define-key menu-bar-ediff-menu [ediff-regions-linewise] + '("Regions Line-by-line..." . ediff-regions-linewise)) + (define-key menu-bar-ediff-menu [ediff-regions-wordwise] + '("Regions Word-by-word..." . ediff-regions-wordwise)) + (define-key menu-bar-ediff-menu [separator-ediff-regions] '("--")) + (define-key menu-bar-ediff-menu [ediff-dir-revision] + '("Directory Revisions..." . ediff-directory-revisions)) + (define-key menu-bar-ediff-menu [ediff-revision] + '("File with Revision..." . ediff-revision)) + (define-key menu-bar-ediff-menu [separator-ediff-directories] '("--")) + (define-key menu-bar-ediff-menu [ediff-directories3] + '("Three Directories..." . ediff-directories3)) + (define-key menu-bar-ediff-menu [ediff-directories] + '("Two Directories..." . ediff-directories)) + (define-key menu-bar-ediff-menu [separator-ediff-files] '("--")) + (define-key menu-bar-ediff-menu [ediff-buffers3] + '("Three Buffers..." . ediff-buffers3)) + (define-key menu-bar-ediff-menu [ediff-files3] + '("Three Files..." . ediff-files3)) + (define-key menu-bar-ediff-menu [ediff-buffers] + '("Two Buffers..." . ediff-buffers)) + (define-key menu-bar-ediff-menu [ediff-files] + '("Two Files..." . ediff-files)) + + ;; define merge menu + (define-key + menu-bar-ediff-merge-menu [ediff-merge-dir-revisions-with-ancestor] + '("Directory Revisions with Ancestor..." + . ediff-merge-directory-revisions-with-ancestor)) + (define-key + menu-bar-ediff-merge-menu [ediff-merge-dir-revisions] + '("Directory Revisions..." . ediff-merge-directory-revisions)) + (define-key + menu-bar-ediff-merge-menu [ediff-merge-revisions-with-ancestor] + '("Revisions with Ancestor..." + . ediff-merge-revisions-with-ancestor)) + (define-key menu-bar-ediff-merge-menu [ediff-merge-revisions] + '("Revisions..." . ediff-merge-revisions)) + (define-key menu-bar-ediff-merge-menu [separator-ediff-merge] '("--")) + (define-key + menu-bar-ediff-merge-menu [ediff-merge-directories-with-ancestor] + '("Directories with Ancestor..." + . ediff-merge-directories-with-ancestor)) + (define-key menu-bar-ediff-merge-menu [ediff-merge-directories] + '("Directories..." . ediff-merge-directories)) + (define-key + menu-bar-ediff-merge-menu [separator-ediff-merge-dirs] '("--")) + (define-key + menu-bar-ediff-merge-menu [ediff-merge-buffers-with-ancestor] + '("Buffers with Ancestor..." . ediff-merge-buffers-with-ancestor)) + (define-key menu-bar-ediff-merge-menu [ediff-merge-buffers] + '("Buffers..." . ediff-merge-buffers)) + (define-key menu-bar-ediff-merge-menu [ediff-merge-files-with-ancestor] + '("Files with Ancestor..." . ediff-merge-files-with-ancestor)) + (define-key menu-bar-ediff-merge-menu [ediff-merge-files] + '("Files..." . ediff-merge-files)) + + ;; define epatch menu + (define-key menu-bar-epatch-menu [ediff-patch-buffer] + '("To a Buffer..." . ediff-patch-buffer)) + (define-key menu-bar-epatch-menu [ediff-patch-file] + '("To a File..." . ediff-patch-file)) + + ;; define ediff miscellanea + (define-key menu-bar-ediff-misc-menu [emultiframe] + '("Toggle use of separate control buffer frame" + . ediff-toggle-multiframe)) + (define-key menu-bar-ediff-misc-menu [eregistry] + '("List Ediff Sessions" . ediff-show-registry)) + (define-key menu-bar-ediff-misc-menu [ediff-cust] + '("Customize Ediff" . ediff-customize)) + (define-key menu-bar-ediff-misc-menu [ediff-doc] + '("Ediff Manual" . ediff-documentation)) + ) + + ) ; emacs case + ) ; ediff-cond-compile-for-xemacs-or-emacs + +;; arrange for autoloads +(if purify-flag + () ; if dumping, autoloads are set up in loaddefs.el + ;; if the user decides to load this file, set up autoloads + ;; compare files and buffers + (autoload 'ediff "ediff" "Compare two files" t) + (autoload 'ediff-files "ediff" "Compare two files" t) + (autoload 'ediff-buffers "ediff" "Compare two bufers" t) + (autoload 'ebuffers "ediff" "Compare two bufers" t) + (autoload 'ediff3 "ediff" "Compare three files" t) + (autoload 'ediff-files3 "ediff" "Compare three files" t) + (autoload 'ediff-buffers3 "ediff" "Compare three bufers" t) + (autoload 'ebuffers3 "ediff" "Compare three bufers" t) + + (autoload 'erevision "ediff" "Compare versions of a file" t) + (autoload 'ediff-revision "ediff" "Compare versions of a file" t) + + ;; compare regions and windows + (autoload 'ediff-windows-wordwise + "ediff" "Compare two windows word-by-word." t) + (autoload 'ediff-regions-wordwise + "ediff" "Compare two regions word-by-word." t) + (autoload 'ediff-windows-linewise + "ediff" "Compare two windows line-by-line." t) + (autoload 'ediff-regions-linewise + "ediff" "Compare two regions line-by-line." t) + + ;; patch + (autoload 'ediff-patch-file "ediff" "Patch a file." t) + (autoload 'epatch "ediff" "Patch a file." t) + (autoload 'ediff-patch-buffer "ediff" "Patch a buffer.") + (autoload 'epatch-buffer "ediff" "Patch a buffer." t) + + ;; merge + (autoload 'ediff-merge "ediff" "Merge two files." t) + (autoload 'ediff-merge-files "ediff" "Merge two files." t) + (autoload 'ediff-merge-files-with-ancestor + "ediff" "Merge two files using a third file as an ancestor." t) + (autoload 'ediff-merge-buffers "ediff" "Merge two buffers." t) + (autoload 'ediff-merge-buffers-with-ancestor + "ediff" "Merge two buffers using a third buffer as an ancestor." t) + + (autoload 'ediff-merge-revisions "ediff" "Merge two versions of a file." t) + (autoload 'ediff-merge-revisions-with-ancestor + "ediff" "Merge two versions of a file." t) + + ;; compare directories + (autoload 'edirs "ediff" "Compare files in two directories." t) + (autoload 'ediff-directories "ediff" "Compare files in two directories." t) + (autoload 'edirs3 "ediff" "Compare files in three directories." t) + (autoload + 'ediff-directories3 "ediff" "Compare files in three directories." t) + + (autoload 'edir-revisions + "ediff" "Compare two versions of a file." t) + (autoload 'ediff-directory-revisions + "ediff" "Compare two versions of a file." t) + + ;; merge directories + (autoload 'edirs-merge "ediff" "Merge files in two directories." t) + (autoload 'ediff-merge-directories + "ediff" "Merge files in two directories." t) + (autoload 'edirs-merge-with-ancestor + "ediff" + "Merge files in two directories using files in a third dir as ancestors." + t) + (autoload 'ediff-merge-directories-with-ancestor + "ediff" + "Merge files in two directories using files in a third dir as ancestors." + t) + + (autoload 'edir-merge-revisions + "ediff" "Merge versions of files in a directory." t) + (autoload 'ediff-merge-directory-revisions + "ediff" "Merge versions of files in a directory." t) + (autoload 'ediff-merge-directory-revisions-with-ancestor + "ediff" + "Merge versions of files in a directory using other versions as ancestors." + t) + (autoload 'edir-merge-revisions-with-ancestor + "ediff" + "Merge versions of files in a directory using other versions as ancestors." + t) + + ;; misc + (autoload 'ediff-show-registry + "ediff-mult" + "Display the registry of active Ediff sessions." + t) + (autoload 'eregistry + "ediff-mult" + "Display the registry of active Ediff sessions." + t) + (autoload 'ediff-documentation + "ediff" + "Display Ediff's manual." + t) + (autoload 'ediff-version + "ediff" + "Show Ediff's version and last modification date." + t) + (autoload 'ediff-toggle-multiframe + "ediff-util" + "Toggle the use of separate frame for Ediff control buffer." + t) + (autoload 'ediff-toggle-use-toolbar + "ediff-util" + "Toggle the use of Ediff toolbar." + t) + + ) ; if purify-flag + + +(provide 'ediff-hook) + + +;;; arch-tag: 512f8656-8a4b-4789-af5d-5c6144498df3 +;;; ediff-hook.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-hook.elc b/xemacs-packages/lisp/ediff/ediff-hook.elc new file mode 100644 index 0000000000000000000000000000000000000000..71f7093631bf16871f86637ced29bcf157cbf8de GIT binary patch literal 5442 zcma(V*>c>*aq}iIPpQfW453tU_W{dGPGa)KIw(6a6)6%OIU$(@3(W3L5sQHbfY$3b z<|y+epO7!G@)NR5)3R(wK@R7Ro%?hyJBM?)dwK@fE=8+UJJUUVPfvG)>l>RFKHO@x z=GNEOnJ-7N2zkJI6Bg|~5=!3-hcZdKdKbu%Cn6>zb^}N*@g7@QVauy)51n0GSz;?o zOCQxj`bv&iAH=Z5p&aqWXm2sz8@Rnpgu!CUlXUTEKJxs;jXi(Q8}MY22cqAnUw0_w zUYCbjk|tv}xk>~mU0Lp)W$oBY{UKZac!xRHr7ygYT~#vXDxEm&$qkgtHZxxYT`i$E zNjW-I3hAzV%+Rf)$xH6i!|w75QOh_LBk_!vqB@a)r-V<30BDc0gabPEWdQ4VD8Q6J zvPhXp1nD z-H}Lq%?_7`YR#U`xEk;}BFb2wdugV4%us31Q_KqjH_3VkvbM7&Wtcb+fGbzr^Gc2r zuDac>Q#mPV${or;0r2$F6f(Lzaa{TbaX7mRVZdhs*AsB&+&+E&L(kuyzxCBSw_n(C z4h|7KMDXxM0FMwnLh$G%0PiAr7s0zP19@|G?#+`M+@acm6Ie z|Dol-`Tr35KP~%@wDSFPEyV1fFSi$9dy%jk<@OS6A0_N#<@OV>{Ul)@FSnbpy-e6o zmD?+@y-L_mm)mQt{p+p$Ey6!h1wI2rHwgbEY(Goe&$afqTl+gZ1np|*^9byJq4nB4 z=4qTM(Vw{e&>PHn#`I=&?%_ku!qhdz0N%Z8P>@a+pt5?3gFI(zEZHTf`H9X;5`Yym zVd<_pKA-jbP|7O=J;E50q2heDjMXZ|v0^k8X12BGqEOsVr4lu(f)ZO5dm?d7Ji5xp zA|0}8{HDP6RB=lg6p6QjCk1IW1lF2~Yq@m9tQ$8(6u@(5H>3*O-ozclTG2G7V~rk* zgp)?gv?(HvOd+f@m=JB5tiEe}0KOcnPtkEhpJh5mpJl4(>oA*QMKNqUm$5S9-8J)Q zq)TQcn=}E1|6Jt5L?NjhR)uPE7q7_m3=KtRI)6xhEg22b2|5hRv=$pqd-wGWBz^Yg z;jEr0h|sBZtZx<8<8|A_tY#Z&u4US`QxKk@wP2gpx$Rg_XJ>ic<3_H}WIn+b8-a?b zDXSpKD&4p3oQvad!mfJIkadNS%+o_%VNu zlK5=pE6wY4u+gBS9+)UYoTBtIdLK^0Snpb%2YT6bFa<4Wxpu4~#f`z7&h%I(qP~PH z-!qQl$Bx-fPo7?uN}RcgfH_);!)(`ODYRT&9BZfp-@&+g|EIp8`#3a@iz10b52k`4XT^ws z{tQ3v644Mz<1e0 How@e_c(u`# literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/ediff-init.el b/xemacs-packages/lisp/ediff/ediff-init.el new file mode 100644 index 00000000..2fc0ceef --- /dev/null +++ b/xemacs-packages/lisp/ediff/ediff-init.el @@ -0,0 +1,1882 @@ +;;; ediff-init.el --- Macros, variables, and defsubsts used by Ediff + +;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +;; 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +;; Author: Michael Kifer + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;;; Code: + +;; Start compiler pacifier +(defvar ediff-metajob-name) +(defvar ediff-meta-buffer) +(defvar pm-color-alist) +(defvar ediff-grab-mouse) +(defvar ediff-mouse-pixel-position) +(defvar ediff-mouse-pixel-threshold) +(defvar ediff-whitespace) +(defvar ediff-multiframe) +(defvar ediff-use-toolbar-p) +(defvar mswindowsx-bitmap-file-path) + +(and noninteractive + (eval-when-compile + (load "ange-ftp" 'noerror))) +;; end pacifier + +;; Is it XEmacs? +(defconst ediff-xemacs-p (featurep 'xemacs)) +;; Is it Emacs? +(defconst ediff-emacs-p (not ediff-xemacs-p)) + +;; This is used to avoid compilation warnings. When emacs/xemacs forms can +;; generate compile time warnings, we use this macro. +;; In this case, the macro will expand into the form that is appropriate to the +;; compiler at hand. +;; Suggested by rms. +(defmacro ediff-cond-compile-for-xemacs-or-emacs (xemacs-form emacs-form) + (if (featurep 'xemacs) + xemacs-form emacs-form)) + +(defvar ediff-force-faces nil + "If t, Ediff will think that it is running on a display that supports faces. +This is provided as a temporary relief for users of face-capable displays +that Ediff doesn't know about.") + +;; Are we running as a window application or on a TTY? +(defsubst ediff-device-type () + (ediff-cond-compile-for-xemacs-or-emacs + (device-type (selected-device)) ; xemacs form + window-system ; emacs form + )) + +;; in XEmacs: device-type is tty on tty and stream in batch. +(defun ediff-window-display-p () + (and (ediff-device-type) (not (memq (ediff-device-type) '(tty pc stream))))) + +;; test if supports faces +(defun ediff-has-face-support-p () + (cond ((ediff-window-display-p)) + (ediff-force-faces) + ((ediff-color-display-p)) + (ediff-emacs-p (memq (ediff-device-type) '(pc))) + (ediff-xemacs-p (memq (ediff-device-type) '(tty pc))) + )) + +;; toolbar support for emacs hasn't been implemented in ediff +(defun ediff-has-toolbar-support-p () + (ediff-cond-compile-for-xemacs-or-emacs + (and (featurep 'toolbar) (console-on-window-system-p)) ; xemacs form + nil ; emacs form + )) + + +(defun ediff-has-gutter-support-p () + (ediff-cond-compile-for-xemacs-or-emacs + (and (featurep 'gutter) (console-on-window-system-p)) ; xemacs form + nil ; emacs form + )) + + +(defun ediff-use-toolbar-p () + (and (ediff-has-toolbar-support-p) ;Can it do it ? + (boundp 'ediff-use-toolbar-p) + ediff-use-toolbar-p)) ;Does the user want it ? + +;; Defines SYMBOL as an advertised local variable. +;; Performs a defvar, then executes `make-variable-buffer-local' on +;; the variable. Also sets the `permanent-local' property, +;; so that `kill-all-local-variables' (called by major-mode setting +;; commands) won't destroy Ediff control variables. +;; +;; Plagiarised from `emerge-defvar-local' for XEmacs. +(defmacro ediff-defvar-local (var value doc) + `(progn + (defvar ,var ,value ,doc) + (make-variable-buffer-local ',var) + (put ',var 'permanent-local t))) + + + +;; Variables that control each Ediff session---local to the control buffer. + +;; Mode variables +;; The buffer in which the A variant is stored. +(ediff-defvar-local ediff-buffer-A nil "") +;; The buffer in which the B variant is stored. +(ediff-defvar-local ediff-buffer-B nil "") +;; The buffer in which the C variant is stored or where the merge buffer lives. +(ediff-defvar-local ediff-buffer-C nil "") +;; Ancestor buffer +(ediff-defvar-local ediff-ancestor-buffer nil "") +;; The Ediff control buffer +(ediff-defvar-local ediff-control-buffer nil "") + +(ediff-defvar-local ediff-temp-indirect-buffer nil + "If t, the buffer is a temporary indirect buffer. +It needs to be killed when we quit the session.") + + +;; Association between buff-type and ediff-buffer-* +(defconst ediff-buffer-alist + '((?A . ediff-buffer-A) + (?B . ediff-buffer-B) + (?C . ediff-buffer-C))) + +;;; Macros +(defmacro ediff-odd-p (arg) + `(eq (logand ,arg 1) 1)) + +(defmacro ediff-buffer-live-p (buf) + `(and ,buf (get-buffer ,buf) (buffer-name (get-buffer ,buf)))) + +(defmacro ediff-get-buffer (arg) + `(cond ((eq ,arg 'A) ediff-buffer-A) + ((eq ,arg 'B) ediff-buffer-B) + ((eq ,arg 'C) ediff-buffer-C) + ((eq ,arg 'Ancestor) ediff-ancestor-buffer) + )) + +(defmacro ediff-get-value-according-to-buffer-type (buf-type list) + `(cond ((eq ,buf-type 'A) (nth 0 ,list)) + ((eq ,buf-type 'B) (nth 1 ,list)) + ((eq ,buf-type 'C) (nth 2 ,list)) + )) + +(defmacro ediff-char-to-buftype (arg) + `(cond ((memq ,arg '(?a ?A)) 'A) + ((memq ,arg '(?b ?B)) 'B) + ((memq ,arg '(?c ?C)) 'C) + )) + + +;; A-list is supposed to be of the form (A . symb) (B . symb)...) +;; where the first part of any association is a buffer type and the second is +;; an appropriate symbol. Given buffer-type, this function returns the +;; symbol. This is used to avoid using `intern' +(defsubst ediff-get-symbol-from-alist (buf-type alist) + (cdr (assoc buf-type alist))) + +(defconst ediff-difference-vector-alist + '((A . ediff-difference-vector-A) + (B . ediff-difference-vector-B) + (C . ediff-difference-vector-C) + (Ancestor . ediff-difference-vector-Ancestor))) + +(defmacro ediff-get-difference (n buf-type) + `(aref + (symbol-value + (ediff-get-symbol-from-alist + ,buf-type ediff-difference-vector-alist)) + ,n)) + +;; Tell if it has been previously determined that the region has +;; no diffs other than the white space and newlines +;; The argument, N, is the diff region number used by Ediff to index the +;; diff vector. It is 1 less than the number seen by the user. +;; Returns: +;; t if the diffs are whitespace in all buffers +;; 'A (in 3-buf comparison only) if there are only whitespace +;; diffs in bufs B and C +;; 'B (in 3-buf comparison only) if there are only whitespace +;; diffs in bufs A and C +;; 'C (in 3-buf comparison only) if there are only whitespace +;; diffs in bufs A and B +;; +;; A Difference Vector has the form: +;; [diff diff diff ...] +;; where each diff has the form: +;; [overlay fine-diff-vector no-fine-diffs-flag state-of-difference] +;; fine-diff-vector is a vector [fine-diff fine-diff fine-diff ...] +;; no-fine-diffs-flag says if there are fine differences. +;; state-of-difference is A, B, C, or nil, indicating which buffer is +;; different from the other two (used only in 3-way jobs). +(defmacro ediff-no-fine-diffs-p (n) + `(aref (ediff-get-difference ,n 'A) 2)) + +(defmacro ediff-get-diff-overlay-from-diff-record (diff-rec) + `(aref ,diff-rec 0)) + +(defmacro ediff-get-diff-overlay (n buf-type) + `(ediff-get-diff-overlay-from-diff-record + (ediff-get-difference ,n ,buf-type))) + +(defmacro ediff-get-fine-diff-vector-from-diff-record (diff-rec) + `(aref ,diff-rec 1)) + +(defmacro ediff-set-fine-diff-vector (n buf-type fine-vec) + `(aset (ediff-get-difference ,n ,buf-type) 1 ,fine-vec)) + +(defmacro ediff-get-state-of-diff (n buf-type) + `(if (ediff-buffer-live-p ediff-buffer-C) + (aref (ediff-get-difference ,n ,buf-type) 3))) +(defmacro ediff-set-state-of-diff (n buf-type val) + `(aset (ediff-get-difference ,n ,buf-type) 3 ,val)) + +(defmacro ediff-get-state-of-merge (n) + `(if ediff-state-of-merge + (aref (aref ediff-state-of-merge ,n) 0))) +(defmacro ediff-set-state-of-merge (n val) + `(if ediff-state-of-merge + (aset (aref ediff-state-of-merge ,n) 0 ,val))) + +(defmacro ediff-get-state-of-ancestor (n) + `(if ediff-state-of-merge + (aref (aref ediff-state-of-merge ,n) 1))) + +;; if flag is t, puts a mark on diff region saying that +;; the differences are in white space only. If flag is nil, +;; the region is marked as essential (i.e., differences are +;; not just in the white space and newlines.) +(defmacro ediff-mark-diff-as-space-only (n flag) + `(aset (ediff-get-difference ,n 'A) 2 ,flag)) + +(defmacro ediff-get-fine-diff-vector (n buf-type) + `(ediff-get-fine-diff-vector-from-diff-record + (ediff-get-difference ,n ,buf-type))) + +;; Macro to switch to BUFFER, evaluate BODY, returns to original buffer. +;; Doesn't save the point and mark. +;; This is `with-current-buffer' with the added test for live buffers." +(defmacro ediff-with-current-buffer (buffer &rest body) + `(if (ediff-buffer-live-p ,buffer) + (save-current-buffer + (set-buffer ,buffer) + ,@body) + (or (eq this-command 'ediff-quit) + (error ediff-KILLED-VITAL-BUFFER)) + )) + + +(defsubst ediff-multiframe-setup-p () + (and (ediff-window-display-p) ediff-multiframe)) + +(defmacro ediff-narrow-control-frame-p () + `(and (ediff-multiframe-setup-p) + (equal ediff-help-message ediff-brief-message-string))) + +(defmacro ediff-3way-comparison-job () + `(memq + ediff-job-name + '(ediff-files3 ediff-buffers3))) +(ediff-defvar-local ediff-3way-comparison-job nil "") + +(defmacro ediff-merge-job () + `(memq + ediff-job-name + '(ediff-merge-files + ediff-merge-buffers + ediff-merge-files-with-ancestor + ediff-merge-buffers-with-ancestor + ediff-merge-revisions + ediff-merge-revisions-with-ancestor))) +(ediff-defvar-local ediff-merge-job nil "") + +(defmacro ediff-patch-job () + `(eq ediff-job-name 'epatch)) + +(defmacro ediff-merge-with-ancestor-job () + `(memq + ediff-job-name + '(ediff-merge-files-with-ancestor + ediff-merge-buffers-with-ancestor + ediff-merge-revisions-with-ancestor))) +(ediff-defvar-local ediff-merge-with-ancestor-job nil "") + +(defmacro ediff-3way-job () + `(or ediff-3way-comparison-job ediff-merge-job)) +(ediff-defvar-local ediff-3way-job nil "") + +;; A diff3 job is like a 3way job, but ediff-merge doesn't require the use +;; of diff3. +(defmacro ediff-diff3-job () + `(or ediff-3way-comparison-job + ediff-merge-with-ancestor-job)) +(ediff-defvar-local ediff-diff3-job nil "") + +(defmacro ediff-windows-job () + `(memq ediff-job-name '(ediff-windows-wordwise ediff-windows-linewise))) +(ediff-defvar-local ediff-windows-job nil "") + +(defmacro ediff-word-mode-job () + `(memq ediff-job-name '(ediff-windows-wordwise ediff-regions-wordwise))) +(ediff-defvar-local ediff-word-mode-job nil "") + +(defmacro ediff-narrow-job () + `(memq ediff-job-name '(ediff-windows-wordwise + ediff-regions-wordwise + ediff-windows-linewise + ediff-regions-linewise))) +(ediff-defvar-local ediff-narrow-job nil "") + +;; Note: ediff-merge-directory-revisions-with-ancestor is not treated as an +;; ancestor metajob, since it behaves differently. +(defsubst ediff-ancestor-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-merge-directories-with-ancestor + ediff-merge-filegroups-with-ancestor))) +(defsubst ediff-revision-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-directory-revisions + ediff-merge-directory-revisions + ediff-merge-directory-revisions-with-ancestor))) +(defsubst ediff-patch-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-multifile-patch))) +;; metajob involving only one group of files, such as multipatch or directory +;; revision +(defsubst ediff-one-filegroup-metajob (&optional metajob) + (or (ediff-revision-metajob metajob) + (ediff-patch-metajob metajob) + ;; add more here + )) +;; jobs suitable for the operation of collecting diffs into a multifile patch +(defsubst ediff-collect-diffs-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-directories + ediff-merge-directories + ediff-merge-directories-with-ancestor + ediff-directory-revisions + ediff-merge-directory-revisions + ediff-merge-directory-revisions-with-ancestor + ;; add more here + ))) +(defsubst ediff-merge-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-merge-directories + ediff-merge-directories-with-ancestor + ediff-merge-directory-revisions + ediff-merge-directory-revisions-with-ancestor + ediff-merge-filegroups-with-ancestor + ;; add more here + ))) + +(defsubst ediff-metajob3 (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-merge-directories-with-ancestor + ediff-merge-filegroups-with-ancestor + ediff-directories3 + ediff-filegroups3))) +(defsubst ediff-comparison-metajob3 (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-directories3 ediff-filegroups3))) + +;; with no argument, checks if we are in ediff-control-buffer +;; with argument, checks if we are in ediff-meta-buffer +(defun ediff-in-control-buffer-p (&optional meta-buf-p) + (and (boundp 'ediff-control-buffer) + (eq (if meta-buf-p ediff-meta-buffer ediff-control-buffer) + (current-buffer)))) + +(defsubst ediff-barf-if-not-control-buffer (&optional meta-buf-p) + (or (ediff-in-control-buffer-p meta-buf-p) + (error "%S: This command runs in Ediff Control Buffer only!" + this-command))) + +(defgroup ediff-highlighting nil + "Hilighting of difference regions in Ediff." + :prefix "ediff-" + :group 'ediff) + +(defgroup ediff-merge nil + "Merging utilities." + :prefix "ediff-" + :group 'ediff) + +(defgroup ediff-hook nil + "Hooks run by Ediff." + :prefix "ediff-" + :group 'ediff) + +;; Hook variables + +(defcustom ediff-before-setup-hook nil + "*Hooks to run before Ediff begins to set up windows and buffers. +This hook can be used to save the previous window config, which can be restored +on ediff-quit or ediff-suspend." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-before-setup-windows-hook nil + "*Hooks to run before Ediff sets its window configuration. +This hook is run every time when Ediff arranges its windows. +This happens each time Ediff detects that the windows were messed up by the +user." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-after-setup-windows-hook nil + "*Hooks to run after Ediff sets its window configuration. +This can be used to set up control window or icon in a desired place." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-before-setup-control-frame-hook nil + "*Hooks run before setting up the frame to display Ediff Control Panel. +Can be used to change control frame parameters to position it where it +is desirable." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-after-setup-control-frame-hook nil + "*Hooks run after setting up the frame to display Ediff Control Panel. +Can be used to move the frame where it is desired." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-startup-hook nil + "*Hooks to run in the control buffer after Ediff has been set up and is ready for the job." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-select-hook nil + "*Hooks to run after a difference has been selected." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-unselect-hook nil + "*Hooks to run after a difference has been unselected." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-prepare-buffer-hook nil + "*Hooks run after buffers A, B, and C are set up. +For each buffer, the hooks are run with that buffer made current." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-load-hook nil + "*Hook run after Ediff is loaded. Can be used to change defaults." + :type 'hook + :group 'ediff-hook) + +(defcustom ediff-mode-hook nil + "*Hook run just after ediff-mode is set up in the control buffer. +This is done before any windows or frames are created. One can use it to +set local variables that determine how the display looks like." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-keymap-setup-hook nil + "*Hook run just after the default bindings in Ediff keymap are set up." + :type 'hook + :group 'ediff-hook) + +(defcustom ediff-display-help-hook nil + "*Hooks run after preparing the help message." + :type 'hook + :group 'ediff-hook) + +(defcustom ediff-suspend-hook nil + "*Hooks to run in the Ediff control buffer when Ediff is suspended." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-quit-hook nil + "*Hooks to run in the Ediff control buffer after finishing Ediff." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-cleanup-hook nil + "*Hooks to run on exiting Ediff but before killing the control and variant buffers." + :type 'hook + :group 'ediff-hook) + +;; Error messages +(defconst ediff-KILLED-VITAL-BUFFER + "You have killed a vital Ediff buffer---you must leave Ediff now!") +(defconst ediff-NO-DIFFERENCES + "Sorry, comparison of identical variants is not what I am made for...") +(defconst ediff-BAD-DIFF-NUMBER + ;; %S stands for this-command, %d - diff number, %d - max diff + "%S: Bad diff region number, %d. Valid numbers are 1 to %d") +(defconst ediff-BAD-INFO (format " +*** The Info file for Ediff, a part of the standard distribution +*** of %sEmacs, does not seem to be properly installed. +*** +*** Please contact your system administrator. " + (if ediff-xemacs-p "X" ""))) + +;; Selective browsing + +(ediff-defvar-local ediff-skip-diff-region-function 'ediff-show-all-diffs + "Function that determines the next/previous diff region to show. +Should return t for regions to be ignored and nil otherwise. +This function gets a region number as an argument. The region number +is the one used internally by Ediff. It is 1 less than the number seen +by the user.") + +(ediff-defvar-local ediff-hide-regexp-matches-function + 'ediff-hide-regexp-matches + "Function to use in determining which regions to hide. +See the documentation string of `ediff-hide-regexp-matches' for details.") +(ediff-defvar-local ediff-focus-on-regexp-matches-function + 'ediff-focus-on-regexp-matches + "Function to use in determining which regions to focus on. +See the documentation string of `ediff-focus-on-regexp-matches' for details.") + +;; Regexp that determines buf A regions to focus on when skipping to diff +(ediff-defvar-local ediff-regexp-focus-A "" "") +;; Regexp that determines buf B regions to focus on when skipping to diff +(ediff-defvar-local ediff-regexp-focus-B "" "") +;; Regexp that determines buf C regions to focus on when skipping to diff +(ediff-defvar-local ediff-regexp-focus-C "" "") +;; connective that determines whether to focus regions that match both or +;; one of the regexps +(ediff-defvar-local ediff-focus-regexp-connective 'and "") + +;; Regexp that determines buf A regions to ignore when skipping to diff +(ediff-defvar-local ediff-regexp-hide-A "" "") +;; Regexp that determines buf B regions to ignore when skipping to diff +(ediff-defvar-local ediff-regexp-hide-B "" "") +;; Regexp that determines buf C regions to ignore when skipping to diff +(ediff-defvar-local ediff-regexp-hide-C "" "") +;; connective that determines whether to hide regions that match both or +;; one of the regexps +(ediff-defvar-local ediff-hide-regexp-connective 'and "") + + +;;; Copying difference regions between buffers. + +;; A list of killed diffs. +;; A diff is saved here if it is replaced by a diff +;; from another buffer. This alist has the form: +;; \((num (buff-object . diff) (buff-object . diff) (buff-object . diff)) ...), +;; where some buffer-objects may be missing. +(ediff-defvar-local ediff-killed-diffs-alist nil "") + +;; Syntax table to use in ediff-forward-word-function +;; This is chosen by a heuristic. The important thing is for all buffers to +;; have the same syntax table. Which is not too important. +(ediff-defvar-local ediff-syntax-table nil "") + + +;; Highlighting +(defcustom ediff-before-flag-bol (if (featurep 'xemacs) (make-glyph "->>") "->>") + "*Flag placed before a highlighted block of differences, if block starts at beginning of a line." + :type 'string + :tag "Region before-flag at beginning of line" + :group 'ediff) + +(defcustom ediff-after-flag-eol (if (featurep 'xemacs) (make-glyph "<<-") "<<-") + "*Flag placed after a highlighted block of differences, if block ends at end of a line." + :type 'string + :tag "Region after-flag at end of line" + :group 'ediff) + +(defcustom ediff-before-flag-mol (if (featurep 'xemacs) (make-glyph "->>") "->>") + "*Flag placed before a highlighted block of differences, if block starts in mid-line." + :type 'string + :tag "Region before-flag in the middle of line" + :group 'ediff) +(defcustom ediff-after-flag-mol (if (featurep 'xemacs) (make-glyph "<<-") "<<-") + "*Flag placed after a highlighted block of differences, if block ends in mid-line." + :type 'string + :tag "Region after-flag in the middle of line" + :group 'ediff) + + +(ediff-defvar-local ediff-use-faces t "") +(defcustom ediff-use-faces t + "If t, differences are highlighted using faces, if device supports faces. +If nil, differences are highlighted using ASCII flags, ediff-before-flag +and ediff-after-flag. On a non-window system, differences are always +highlighted using ASCII flags." + :type 'boolean + :group 'ediff-highlighting) + +;; this indicates that diff regions are word-size, so fine diffs are +;; permanently nixed; used in ediff-windows-wordwise and ediff-regions-wordwise +(ediff-defvar-local ediff-word-mode nil "") +;; Name of the job (ediff-files, ediff-windows, etc.) +(ediff-defvar-local ediff-job-name nil "") + +;; Narrowing and ediff-region/windows support +;; This is a list (overlay-A overlay-B overlay-C) +;; If set, Ediff compares only those parts of buffers A/B/C that lie within +;; the bounds of these overlays. +(ediff-defvar-local ediff-narrow-bounds nil "") + +;; List (overlay-A overlay-B overlay-C), where each overlay spans the +;; entire corresponding buffer. +(ediff-defvar-local ediff-wide-bounds nil "") + +;; Current visibility boundaries in buffers A, B, and C. +;; This is also a list of overlays. When the user toggles narrow/widen, +;; this list changes from ediff-wide-bounds to ediff-narrow-bounds. +;; and back. +(ediff-defvar-local ediff-visible-bounds nil "") + +(ediff-defvar-local ediff-start-narrowed t + "Non-nil means start narrowed, if doing ediff-windows-* or ediff-regions-*") +(ediff-defvar-local ediff-quit-widened t + "*Non-nil means: when finished, Ediff widens buffers A/B. +Actually, Ediff restores the scope of visibility that existed at startup.") + +(defcustom ediff-keep-variants t + "*nil means prompt to remove unmodified buffers A/B/C at session end. +Supplying a prefix argument to the quit command `q' temporarily reverses the +meaning of this variable." + :type 'boolean + :group 'ediff) + +(ediff-defvar-local ediff-highlight-all-diffs t "") +(defcustom ediff-highlight-all-diffs t + "If nil, only the selected differences are highlighted. +Otherwise, all difference regions are highlighted, but the selected region is +shown in brighter colors." + :type 'boolean + :group 'ediff-highlighting) + + +;; The suffix of the control buffer name. +(ediff-defvar-local ediff-control-buffer-suffix nil "") +;; Same as ediff-control-buffer-suffix, but without <,>. +;; It's a number rather than string. +(ediff-defvar-local ediff-control-buffer-number nil "") + + +;; The original values of ediff-protected-variables for buffer A +(ediff-defvar-local ediff-buffer-values-orig-A nil "") +;; The original values of ediff-protected-variables for buffer B +(ediff-defvar-local ediff-buffer-values-orig-B nil "") +;; The original values of ediff-protected-variables for buffer C +(ediff-defvar-local ediff-buffer-values-orig-C nil "") +;; The original values of ediff-protected-variables for buffer Ancestor +(ediff-defvar-local ediff-buffer-values-orig-Ancestor nil "") + +;; association between buff-type and ediff-buffer-values-orig-* +(defconst ediff-buffer-values-orig-alist + '((A . ediff-buffer-values-orig-A) + (B . ediff-buffer-values-orig-B) + (C . ediff-buffer-values-orig-C) + (Ancestor . ediff-buffer-values-orig-Ancestor))) + +;; Buffer-local variables to be saved then restored during Ediff sessions +(defconst ediff-protected-variables '( + ;;buffer-read-only + mode-line-format)) + +;; Vector of differences between the variants. Each difference is +;; represented by a vector of two overlays plus a vector of fine diffs, +;; plus a no-fine-diffs flag. The first overlay spans the +;; difference region in the A buffer and the second overlays the diff in +;; the B buffer. If a difference section is empty, the corresponding +;; overlay's endpoints coincide. +;; +;; The precise form of a Difference Vector for one buffer is: +;; [diff diff diff ...] +;; where each diff has the form: +;; [diff-overlay fine-diff-vector no-fine-diffs-flag state-of-diff] +;; fine-diff-vector is a vector [fine-diff-overlay fine-diff-overlay ...] +;; no-fine-diffs-flag says if there are fine differences. +;; state-of-difference is A, B, C, or nil, indicating which buffer is +;; different from the other two (used only in 3-way jobs. +(ediff-defvar-local ediff-difference-vector-A nil "") +(ediff-defvar-local ediff-difference-vector-B nil "") +(ediff-defvar-local ediff-difference-vector-C nil "") +(ediff-defvar-local ediff-difference-vector-Ancestor nil "") +;; A-list of diff vector types associated with buffer types +(defconst ediff-difference-vector-alist + '((A . ediff-difference-vector-A) + (B . ediff-difference-vector-B) + (C . ediff-difference-vector-C) + (Ancestor . ediff-difference-vector-Ancestor))) + +;; [ status status status ...] +;; Each status: [state-of-merge state-of-ancestor] +;; state-of-merge is default-A, default-B, prefer-A, or prefer-B. It +;; indicates the way a diff region was created in buffer C. +;; state-of-ancestor says if the corresponding region in ancestor buffer is +;; empty. +(ediff-defvar-local ediff-state-of-merge nil "") + +;; The difference that is currently selected. +(ediff-defvar-local ediff-current-difference -1 "") +;; Number of differences found. +(ediff-defvar-local ediff-number-of-differences nil "") + +;; Buffer containing the output of diff, which is used by Ediff to step +;; through files. +(ediff-defvar-local ediff-diff-buffer nil "") +;; Like ediff-diff-buffer, but contains context diff. It is not used by +;; Ediff, but it is saved in a file, if user requests so. +(ediff-defvar-local ediff-custom-diff-buffer nil "") +;; Buffer used for diff-style fine differences between regions. +(ediff-defvar-local ediff-fine-diff-buffer nil "") +;; Temporary buffer used for computing fine differences. +(defconst ediff-tmp-buffer " *ediff-tmp*" "") +;; Buffer used for messages +(defconst ediff-msg-buffer " *ediff-message*" "") +;; Buffer containing the output of diff when diff returns errors. +(ediff-defvar-local ediff-error-buffer nil "") +;; Buffer to display debug info +(ediff-defvar-local ediff-debug-buffer "*ediff-debug*" "") + +;; List of ediff control panels associated with each buffer A/B/C/Ancestor. +;; Not used any more, but may be needed in the future. +(ediff-defvar-local ediff-this-buffer-ediff-sessions nil "") + +;; to be deleted in due time +;; List of difference overlays disturbed by working with the current diff. +(defvar ediff-disturbed-overlays nil "") + +;; Priority of non-selected overlays. +(defvar ediff-shadow-overlay-priority 100 "") + +(defcustom ediff-version-control-package 'vc + "Version control package used. +Currently, Ediff supports vc.el, rcs.el, pcl-cvs.el, and generic-sc.el. The +standard Emacs interface to RCS, CVS, SCCS, etc., is vc.el. However, some +people find the other two packages more convenient. Set this variable to the +appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire." + :type 'symbol + :group 'ediff) + +(defcustom ediff-coding-system-for-read 'raw-text + "*The coding system for read to use when running the diff program as a subprocess. +In most cases, the default will do. However, under certain circumstances in +Windows NT/98/95 you might need to use something like 'raw-text-dos here. +So, if the output that your diff program sends to Emacs contains extra ^M's, +you might need to experiment here, if the default or 'raw-text-dos doesn't +work." + :type 'symbol + :group 'ediff) + +(defcustom ediff-coding-system-for-write 'no-conversion + "*The coding system for write to use when writing out difference regions +to temp files when Ediff needs to find fine differences." + :type 'symbol + :group 'ediff) + + +(ediff-cond-compile-for-xemacs-or-emacs + (progn ; xemacs + (defalias 'ediff-read-event 'next-command-event) + (defalias 'ediff-overlayp 'extentp) + (defalias 'ediff-make-overlay 'make-extent) + (defalias 'ediff-delete-overlay 'delete-extent)) + (progn ; emacs + (defalias 'ediff-read-event 'read-event) + (defalias 'ediff-overlayp 'overlayp) + (defalias 'ediff-make-overlay 'make-overlay) + (defalias 'ediff-delete-overlay 'delete-overlay)) + ) + +;; Check the current version against the major and minor version numbers +;; using op: cur-vers op major.minor If emacs-major-version or +;; emacs-minor-version are not defined, we assume that the current version +;; is hopelessly outdated. We assume that emacs-major-version and +;; emacs-minor-version are defined. Otherwise, for Emacs/XEmacs 19, if the +;; current minor version is < 10 (xemacs) or < 23 (emacs) the return value +;; will be nil (when op is =, >, or >=) and t (when op is <, <=), which may be +;; incorrect. However, this gives correct result in our cases, since we are +;; testing for sufficiently high Emacs versions. +(defun ediff-check-version (op major minor &optional type-of-emacs) + (if (and (boundp 'emacs-major-version) (boundp 'emacs-minor-version)) + (and (cond ((eq type-of-emacs 'xemacs) ediff-xemacs-p) + ((eq type-of-emacs 'emacs) ediff-emacs-p) + (t t)) + (cond ((eq op '=) (and (= emacs-minor-version minor) + (= emacs-major-version major))) + ((memq op '(> >= < <=)) + (and (or (funcall op emacs-major-version major) + (= emacs-major-version major)) + (if (= emacs-major-version major) + (funcall op emacs-minor-version minor) + t))) + (t + (error "%S: Invalid op in ediff-check-version" op)))) + (cond ((memq op '(= > >=)) nil) + ((memq op '(< <=)) t)))) + + +(defun ediff-color-display-p () + (condition-case nil + (ediff-cond-compile-for-xemacs-or-emacs + (eq (device-class (selected-device)) 'color) ; xemacs form + (if (fboundp 'display-color-p) ; emacs form + (display-color-p) + (x-display-color-p)) + ) + (error nil))) + + +;; A var local to each control panel buffer. Indicates highlighting style +;; in effect for this buffer: `face', `ascii', +;; `off' -- turned off \(on a dumb terminal only\). +(ediff-defvar-local ediff-highlighting-style + (if (and (ediff-has-face-support-p) ediff-use-faces) 'face 'ascii) + "") + + +(if (ediff-has-face-support-p) + (ediff-cond-compile-for-xemacs-or-emacs + (progn ; xemacs + (defalias 'ediff-valid-color-p 'valid-color-name-p) + (defalias 'ediff-get-face 'get-face)) + (progn ; emacs + (defalias 'ediff-valid-color-p (if (fboundp 'color-defined-p) + 'color-defined-p + 'x-color-defined-p)) + (defalias 'ediff-get-face 'internal-get-face)) + )) + +(if (ediff-window-display-p) + (ediff-cond-compile-for-xemacs-or-emacs + (progn ; xemacs + (defalias 'ediff-display-pixel-width 'device-pixel-width) + (defalias 'ediff-display-pixel-height 'device-pixel-height)) + (progn ; emacs + (defalias 'ediff-display-pixel-width + (if (fboundp 'display-pixel-width) + 'display-pixel-width + 'x-display-pixel-width)) + (defalias 'ediff-display-pixel-height + (if (fboundp 'display-pixel-height) + 'display-pixel-height + 'x-display-pixel-height))) + )) + +;; A-list of current-diff-overlay symbols associated with buf types +(defconst ediff-current-diff-overlay-alist + '((A . ediff-current-diff-overlay-A) + (B . ediff-current-diff-overlay-B) + (C . ediff-current-diff-overlay-C) + (Ancestor . ediff-current-diff-overlay-Ancestor))) + +;; A-list of current-diff-face-* symbols associated with buf types +(defconst ediff-current-diff-face-alist + '((A . ediff-current-diff-A) + (B . ediff-current-diff-B) + (C . ediff-current-diff-C) + (Ancestor . ediff-current-diff-Ancestor))) + + +(defun ediff-set-overlay-face (extent face) + (ediff-overlay-put extent 'face face) + (ediff-overlay-put extent 'help-echo 'ediff-region-help-echo)) + +(defun ediff-region-help-echo (extent-or-window &optional overlay point) + (unless overlay + (setq overlay extent-or-window)) + (let ((is-current (ediff-overlay-get overlay 'ediff)) + (face (ediff-overlay-get overlay 'face)) + (diff-num (ediff-overlay-get overlay 'ediff-diff-num)) + face-help) + + ;; This happens only for refinement overlays + (if (stringp face) + (setq face (intern face))) + (setq face-help (and face (get face 'ediff-help-echo))) + + (cond ((and is-current diff-num) ; current diff region + (format "Difference region %S -- current" (1+ diff-num))) + (face-help) ; refinement of current diff region + (diff-num ; non-current + (format "Difference region %S -- non-current" (1+ diff-num))) + (t "")) ; none + )) + + +(defun ediff-set-face-pixmap (face pixmap) + "Set face pixmap on a monochrome display." + (if (and (ediff-window-display-p) (not (ediff-color-display-p))) + (condition-case nil + (set-face-background-pixmap face pixmap) + (error + (message "Pixmap not found for %S: %s" (face-name face) pixmap) + (sit-for 1))))) + +(defun ediff-hide-face (face) + (if (and (ediff-has-face-support-p) + (boundp 'add-to-list) + (boundp 'facemenu-unlisted-faces)) + (add-to-list 'facemenu-unlisted-faces face))) + + + +(defface ediff-current-diff-A + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "firebrick" :background "pale green")) + (((class color)) + (:foreground "blue3" :background "yellow3")) + (t (:inverse-video t))) + '((((type tty)) (:foreground "blue3" :background "yellow3")) + (((class color)) (:foreground "firebrick" :background "pale green")) + (t (:inverse-video t)))) + "Face for highlighting the selected difference in buffer A." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-current-diff-face-A 'ediff-current-diff-A + "Face for highlighting the selected difference in buffer A. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-current-diff-A' +this variable represents.") +(ediff-hide-face ediff-current-diff-face-A) +;; Until custom.el for XEmacs starts supporting :inverse-video we do this. +;; This means that some user customization may be trashed. +(if (and ediff-xemacs-p + (ediff-has-face-support-p) + (not (ediff-color-display-p))) + (copy-face 'modeline ediff-current-diff-face-A)) + + + +(defface ediff-current-diff-B + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "DarkOrchid" :background "Yellow")) + (((class color)) + (:foreground "magenta3" :background "yellow3" + :weight bold)) + (t (:inverse-video t))) + '((((type tty)) (:foreground "magenta3" :background "yellow3" + :weight bold)) + (((class color)) (:foreground "DarkOrchid" :background "Yellow")) + (t (:inverse-video t)))) + "Face for highlighting the selected difference in buffer B." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-current-diff-face-B 'ediff-current-diff-B + "Face for highlighting the selected difference in buffer B. + this variable. Instead, use the customization +widget to customize the actual face `ediff-current-diff-B' +this variable represents.") +(ediff-hide-face ediff-current-diff-face-B) +;; Until custom.el for XEmacs starts supporting :inverse-video we do this. +;; This means that some user customization may be trashed. +(if (and ediff-xemacs-p + (ediff-has-face-support-p) + (not (ediff-color-display-p))) + (copy-face 'modeline ediff-current-diff-face-B)) + + +(defface ediff-current-diff-C + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "Navy" :background "Pink")) + (((class color)) + (:foreground "cyan3" :background "yellow3" :weight bold)) + (t (:inverse-video t))) + '((((type tty)) (:foreground "cyan3" :background "yellow3" :weight bold)) + (((class color)) (:foreground "Navy" :background "Pink")) + (t (:inverse-video t)))) + "Face for highlighting the selected difference in buffer C." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-current-diff-face-C 'ediff-current-diff-C + "Face for highlighting the selected difference in buffer C. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-current-diff-C' +this variable represents.") +(ediff-hide-face ediff-current-diff-face-C) +;; Until custom.el for XEmacs starts supporting :inverse-video we do this. +;; This means that some user customization may be trashed. +(if (and ediff-xemacs-p + (ediff-has-face-support-p) + (not (ediff-color-display-p))) + (copy-face 'modeline ediff-current-diff-face-C)) + + +(defface ediff-current-diff-Ancestor + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "Black" :background "VioletRed")) + (((class color)) + (:foreground "black" :background "magenta3")) + (t (:inverse-video t))) + '((((type tty)) (:foreground "black" :background "magenta3")) + (((class color)) (:foreground "Black" :background "VioletRed")) + (t (:inverse-video t)))) + "Face for highlighting the selected difference in buffer Ancestor." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-current-diff-face-Ancestor 'ediff-current-diff-Ancestor + "Face for highlighting the selected difference in buffer Ancestor. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-current-diff-Ancestor' +this variable represents.") +(ediff-hide-face ediff-current-diff-face-Ancestor) +;; Until custom.el for XEmacs starts supporting :inverse-video we do this. +;; This means that some user customization may be trashed. +(if (and ediff-xemacs-p + (ediff-has-face-support-p) + (not (ediff-color-display-p))) + (copy-face 'modeline ediff-current-diff-face-Ancestor)) + + +(defface ediff-fine-diff-A + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "Navy" :background "sky blue")) + (((class color)) + (:foreground "white" :background "sky blue" :weight bold)) + (t (:underline t :stipple "gray3"))) + '((((type tty)) (:foreground "white" :background "sky blue" :weight bold)) + (((class color)) (:foreground "Navy" :background "sky blue")) + (t (:underline t :stipple "gray3")))) + "Face for highlighting the refinement of the selected diff in buffer A." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-fine-diff-face-A 'ediff-fine-diff-A + "Face for highlighting the fine differences in buffer A. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-fine-diff-A' +this variable represents.") +(ediff-hide-face ediff-fine-diff-face-A) + +(defface ediff-fine-diff-B + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "Black" :background "cyan")) + (((class color)) + (:foreground "magenta3" :background "cyan3")) + (t (:underline t :stipple "gray3"))) + '((((type tty)) (:foreground "magenta3" :background "cyan3")) + (((class color)) (:foreground "Black" :background "cyan")) + (t (:underline t :stipple "gray3")))) + "Face for highlighting the refinement of the selected diff in buffer B." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-fine-diff-face-B 'ediff-fine-diff-B + "Face for highlighting the fine differences in buffer B. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-fine-diff-B' +this variable represents.") +(ediff-hide-face ediff-fine-diff-face-B) + +(defface ediff-fine-diff-C + (if ediff-emacs-p + '((((type pc)) + (:foreground "white" :background "Turquoise")) + (((class color) (min-colors 16)) + (:foreground "Black" :background "Turquoise")) + (((class color)) + (:foreground "yellow3" :background "Turquoise" + :weight bold)) + (t (:underline t :stipple "gray3"))) + '((((type tty)) (:foreground "yellow3" :background "Turquoise" + :weight bold)) + (((type pc)) (:foreground "white" :background "Turquoise")) + (((class color)) (:foreground "Black" :background "Turquoise")) + (t (:underline t :stipple "gray3")))) + "Face for highlighting the refinement of the selected diff in buffer C." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-fine-diff-face-C 'ediff-fine-diff-C + "Face for highlighting the fine differences in buffer C. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-fine-diff-C' +this variable represents.") +(ediff-hide-face ediff-fine-diff-face-C) + +(defface ediff-fine-diff-Ancestor + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "Black" :background "Green")) + (((class color)) + (:foreground "red3" :background "green")) + (t (:underline t :stipple "gray3"))) + '((((type tty)) (:foreground "red3" :background "green")) + (((class color)) (:foreground "Black" :background "Green")) + (t (:underline t :stipple "gray3")))) + "Face for highlighting the refinement of the selected diff in the ancestor buffer. +At present, this face is not used and no fine differences are computed for the +ancestor buffer." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-fine-diff-face-Ancestor 'ediff-fine-diff-Ancestor + "Face for highlighting the fine differences in buffer Ancestor. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-fine-diff-Ancestor' +this variable represents.") +(ediff-hide-face ediff-fine-diff-face-Ancestor) + +;; Some installs don't have stipple or Stipple. So, try them in turn. +(defvar stipple-pixmap + (cond ((not (ediff-has-face-support-p)) nil) + ((and (boundp 'x-bitmap-file-path) + (locate-library "stipple" t x-bitmap-file-path)) "stipple") + ((and (boundp 'mswindowsx-bitmap-file-path) + (locate-library "stipple" t mswindowsx-bitmap-file-path)) "stipple") + (t "Stipple"))) + +(defface ediff-even-diff-A + (if ediff-emacs-p + `((((type pc)) + (:foreground "green3" :background "light grey")) + (((class color) (min-colors 16)) + (:foreground "Black" :background "light grey")) + (((class color)) + (:foreground "red3" :background "light grey" + :weight bold)) + (t (:italic t :stipple ,stipple-pixmap))) + `((((type tty)) (:foreground "red3" :background "light grey" + :weight bold)) + (((type pc)) (:foreground "green3" :background "light grey")) + (((class color)) (:foreground "Black" :background "light grey")) + (t (:italic t :stipple ,stipple-pixmap)))) + "Face for highlighting even-numbered non-current differences in buffer A." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-even-diff-face-A 'ediff-even-diff-A + "Face for highlighting even-numbered non-current differences in buffer A. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-even-diff-A' +this variable represents.") +(ediff-hide-face ediff-even-diff-face-A) + +(defface ediff-even-diff-B + (if ediff-emacs-p + `((((class color) (min-colors 16)) + (:foreground "White" :background "Grey")) + (((class color)) + (:foreground "blue3" :background "Grey" :weight bold)) + (t (:italic t :stipple ,stipple-pixmap))) + `((((type tty)) (:foreground "blue3" :background "Grey" :weight bold)) + (((class color)) (:foreground "White" :background "Grey")) + (t (:italic t :stipple ,stipple-pixmap)))) + "Face for highlighting even-numbered non-current differences in buffer B." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-even-diff-face-B 'ediff-even-diff-B + "Face for highlighting even-numbered non-current differences in buffer B. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-even-diff-B' +this variable represents.") +(ediff-hide-face ediff-even-diff-face-B) + +(defface ediff-even-diff-C + (if ediff-emacs-p + `((((type pc)) + (:foreground "yellow3" :background "light grey")) + (((class color) (min-colors 16)) + (:foreground "Black" :background "light grey")) + (((class color)) + (:foreground "yellow3" :background "light grey" + :weight bold)) + (t (:italic t :stipple ,stipple-pixmap))) + `((((type tty)) (:foreground "yellow3" :background "light grey" + :weight bold)) + (((type pc)) (:foreground "yellow3" :background "light grey")) + (((class color)) (:foreground "Black" :background "light grey")) + (t (:italic t :stipple ,stipple-pixmap)))) + "Face for highlighting even-numbered non-current differences in buffer C." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-even-diff-face-C 'ediff-even-diff-C + "Face for highlighting even-numbered non-current differences in buffer C. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-even-diff-C' +this variable represents.") +(ediff-hide-face ediff-even-diff-face-C) + +(defface ediff-even-diff-Ancestor + (if ediff-emacs-p + `((((type pc)) + (:foreground "cyan3" :background "light grey")) + (((class color) (min-colors 16)) + (:foreground "White" :background "Grey")) + (((class color)) + (:foreground "cyan3" :background "light grey" + :weight bold)) + (t (:italic t :stipple ,stipple-pixmap))) + `((((type tty)) (:foreground "cyan3" :background "light grey" + :weight bold)) + (((type pc)) (:foreground "cyan3" :background "light grey")) + (((class color)) (:foreground "White" :background "Grey")) + (t (:italic t :stipple ,stipple-pixmap)))) + "Face for highlighting even-numbered non-current differences in the ancestor buffer." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-even-diff-face-Ancestor 'ediff-even-diff-Ancestor + "Face for highlighting even-numbered non-current differences in buffer Ancestor. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-even-diff-Ancestor' +this variable represents.") +(ediff-hide-face ediff-even-diff-face-Ancestor) + +;; Association between buffer types and even-diff-face symbols +(defconst ediff-even-diff-face-alist + '((A . ediff-even-diff-A) + (B . ediff-even-diff-B) + (C . ediff-even-diff-C) + (Ancestor . ediff-even-diff-Ancestor))) + +(defface ediff-odd-diff-A + (if ediff-emacs-p + '((((type pc)) + (:foreground "green3" :background "gray40")) + (((class color) (min-colors 16)) + (:foreground "White" :background "Grey")) + (((class color)) + (:foreground "red3" :background "black" :weight bold)) + (t (:italic t :stipple "gray1"))) + '((((type tty)) (:foreground "red3" :background "black" :weight bold)) + (((type pc)) (:foreground "green3" :background "gray40")) + (((class color)) (:foreground "White" :background "Grey")) + (t (:italic t :stipple "gray1")))) + "Face for highlighting odd-numbered non-current differences in buffer A." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-odd-diff-face-A 'ediff-odd-diff-A + "Face for highlighting odd-numbered non-current differences in buffer A. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-odd-diff-A' +this variable represents.") +(ediff-hide-face ediff-odd-diff-face-A) + + +(defface ediff-odd-diff-B + (if ediff-emacs-p + '((((type pc)) + (:foreground "White" :background "gray40")) + (((class color) (min-colors 16)) + (:foreground "Black" :background "light grey")) + (((class color)) + (:foreground "cyan3" :background "black" :weight bold)) + (t (:italic t :stipple "gray1"))) + '((((type tty)) (:foreground "cyan3" :background "black" :weight bold)) + (((type pc)) (:foreground "White" :background "gray40")) + (((class color)) (:foreground "Black" :background "light grey")) + (t (:italic t :stipple "gray1")))) + "Face for highlighting odd-numbered non-current differences in buffer B." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-odd-diff-face-B 'ediff-odd-diff-B + "Face for highlighting odd-numbered non-current differences in buffer B. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-odd-diff-B' +this variable represents.") +(ediff-hide-face ediff-odd-diff-face-B) + +(defface ediff-odd-diff-C + (if ediff-emacs-p + '((((type pc)) + (:foreground "yellow3" :background "gray40")) + (((class color) (min-colors 16)) + (:foreground "White" :background "Grey")) + (((class color)) + (:foreground "yellow3" :background "black" :weight bold)) + (t (:italic t :stipple "gray1"))) + '((((type tty)) (:foreground "yellow3" :background "black" :weight bold)) + (((type pc)) (:foreground "yellow3" :background "gray40")) + (((class color)) (:foreground "White" :background "Grey")) + (t (:italic t :stipple "gray1")))) + "Face for highlighting odd-numbered non-current differences in buffer C." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-odd-diff-face-C 'ediff-odd-diff-C + "Face for highlighting odd-numbered non-current differences in buffer C. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-odd-diff-C' +this variable represents.") +(ediff-hide-face ediff-odd-diff-face-C) + +(defface ediff-odd-diff-Ancestor + (if ediff-emacs-p + '((((class color) (min-colors 16)) + (:foreground "cyan3" :background "gray40")) + (((class color)) + (:foreground "green3" :background "black" :weight bold)) + (t (:italic t :stipple "gray1"))) + '((((type tty)) (:foreground "green3" :background "black" :weight bold)) + (((class color)) (:foreground "cyan3" :background "gray40")) + (t (:italic t :stipple "gray1")))) + "Face for highlighting odd-numbered non-current differences in the ancestor buffer." + :group 'ediff-highlighting) +;; An internal variable. Ediff takes the face from here. When unhighlighting, +;; this variable is set to nil, then again to the appropriate face. +(defvar ediff-odd-diff-face-Ancestor 'ediff-odd-diff-Ancestor + "Face for highlighting odd-numbered non-current differences in buffer Ancestor. +DO NOT CHANGE this variable. Instead, use the customization +widget to customize the actual face object `ediff-odd-diff-Ancestor' +this variable represents.") +(ediff-hide-face ediff-odd-diff-face-Ancestor) + +;; Association between buffer types and odd-diff-face symbols +(defconst ediff-odd-diff-face-alist + '((A . ediff-odd-diff-A) + (B . ediff-odd-diff-B) + (C . ediff-odd-diff-C) + (Ancestor . ediff-odd-diff-Ancestor))) + +;; A-list of fine-diff face symbols associated with buffer types +(defconst ediff-fine-diff-face-alist + '((A . ediff-fine-diff-A) + (B . ediff-fine-diff-B) + (C . ediff-fine-diff-C) + (Ancestor . ediff-fine-diff-Ancestor))) + +;; Help echo +(put ediff-fine-diff-face-A 'ediff-help-echo + "A `refinement' of the current difference region") +(put ediff-fine-diff-face-B 'ediff-help-echo + "A `refinement' of the current difference region") +(put ediff-fine-diff-face-C 'ediff-help-echo + "A `refinement' of the current difference region") +(put ediff-fine-diff-face-Ancestor 'ediff-help-echo + "A `refinement' of the current difference region") + +(add-hook 'ediff-quit-hook 'ediff-cleanup-mess) +(add-hook 'ediff-suspend-hook 'ediff-default-suspend-function) + + +;;; Overlays + +(ediff-defvar-local ediff-current-diff-overlay-A nil + "Overlay for the current difference region in buffer A.") +(ediff-defvar-local ediff-current-diff-overlay-B nil + "Overlay for the current difference region in buffer B.") +(ediff-defvar-local ediff-current-diff-overlay-C nil + "Overlay for the current difference region in buffer C.") +(ediff-defvar-local ediff-current-diff-overlay-Ancestor nil + "Overlay for the current difference region in the ancestor buffer.") + +;; Compute priority of a current ediff overlay. +(defun ediff-highest-priority (start end buffer) + (let ((pos (max 1 (1- start))) + ovr-list) + (ediff-cond-compile-for-xemacs-or-emacs + (1+ ediff-shadow-overlay-priority) ; xemacs form + ;; emacs form + (ediff-with-current-buffer buffer + (while (< pos (min (point-max) (1+ end))) + (setq ovr-list (append (overlays-at pos) ovr-list)) + (setq pos (next-overlay-change pos))) + (+ 1 ediff-shadow-overlay-priority + (apply 'max + (cons + 1 + (mapcar + (lambda (ovr) + (if (and ovr + ;; exclude ediff overlays from priority + ;; calculation, or else priority will keep + ;; increasing + (null (ediff-overlay-get ovr 'ediff)) + (null (ediff-overlay-get ovr 'ediff-diff-num))) + ;; use the overlay priority or 0 + (or (ediff-overlay-get ovr 'priority) 0) + 0)) + ovr-list) + ) + ))) + ) ; ediff-cond-compile-for-xemacs-or-emacs + )) + + +(defvar ediff-toggle-read-only-function nil + "*Specifies the function to be used to toggle read-only. +If nil, Ediff tries to deduce the function from the binding of C-x C-q. +Normally, this is the `toggle-read-only' function, but, if version +control is used, it could be `vc-toggle-read-only' or `rcs-toggle-read-only'.") + +(defcustom ediff-make-buffers-readonly-at-startup nil + "*Make all variant buffers read-only when Ediff starts up. +This property can be toggled interactively." + :type 'boolean + :group 'ediff) + + +;;; Misc + +;; if nil, this silences some messages +(defconst ediff-verbose-p t) + +(defcustom ediff-autostore-merges 'group-jobs-only + "*Save the results of merge jobs automatically. +nil means don't save automatically. t means always save. Anything else +means save automatically only if the merge job is part of a group of jobs, such +as `ediff-merge-directory' or `ediff-merge-directory-revisions'." + :type '(choice (const nil) (const t) (const group-jobs-only)) + :group 'ediff-merge) +(make-variable-buffer-local 'ediff-autostore-merges) + +;; file where the result of the merge is to be saved. used internally +(ediff-defvar-local ediff-merge-store-file nil "") + +(defcustom ediff-merge-filename-prefix "merge_" + "*Prefix to be attached to saved merge buffers." + :type 'string + :group 'ediff-merge) + +(defcustom ediff-no-emacs-help-in-control-buffer nil + "*Non-nil means C-h should not invoke Emacs help in control buffer. +Instead, C-h would jump to previous difference." + :type 'boolean + :group 'ediff) + +;; This is the same as temporary-file-directory from Emacs 20.3. +;; Copied over here because XEmacs doesn't have this variable. +(defcustom ediff-temp-file-prefix + (file-name-as-directory + (cond ((boundp 'temporary-file-directory) temporary-file-directory) + ((fboundp 'temp-directory) (temp-directory)) + (t "/tmp/"))) +;;; (file-name-as-directory +;;; (cond ((memq system-type '(ms-dos windows-nt)) +;;; (or (getenv "TEMP") (getenv "TMPDIR") (getenv "TMP") "c:/temp")) +;;; ((memq system-type '(vax-vms axp-vms)) +;;; (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "SYS$SCRATCH:")) +;;; (t +;;; (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp")))) + "*Prefix to put on Ediff temporary file names. +Do not start with `~/' or `~USERNAME/'." + :type 'string + :group 'ediff) + +(defcustom ediff-temp-file-mode 384 ; u=rw only + "*Mode for Ediff temporary files." + :type 'integer + :group 'ediff) + +;; Metacharacters that have to be protected from the shell when executing +;; a diff/diff3 command. +(defcustom ediff-metachars "[ \t\n!\"#$&'()*;<=>?[\\^`{|~]" + "Regexp that matches characters that must be quoted with `\\' in shell command line. +This default should work without changes." + :type 'string + :group 'ediff) + +;; needed to simulate frame-char-width in XEmacs. +(defvar ediff-H-glyph (if (featurep 'xemacs) (make-glyph "H"))) + + +;; Temporary file used for refining difference regions in buffer A. +(ediff-defvar-local ediff-temp-file-A nil "") +;; Temporary file used for refining difference regions in buffer B. +(ediff-defvar-local ediff-temp-file-B nil "") +;; Temporary file used for refining difference regions in buffer C. +(ediff-defvar-local ediff-temp-file-C nil "") + + +(defun ediff-file-remote-p (file-name) + (file-remote-p file-name)) + +;; File for which we can get attributes, such as size or date +(defun ediff-listable-file (file-name) + (let ((handler (find-file-name-handler file-name 'file-local-copy))) + (or (null handler) (eq handler 'dired-handler-fn)))) + + +(defsubst ediff-frame-unsplittable-p (frame) + (cdr (assq 'unsplittable (frame-parameters frame)))) + +(defsubst ediff-get-next-window (wind prev-wind) + (cond ((window-live-p wind) wind) + (prev-wind (next-window wind)) + (t (selected-window)) + )) + + +(defsubst ediff-kill-buffer-carefully (buf) + "Kill buffer BUF if it exists." + (if (ediff-buffer-live-p buf) + (kill-buffer (get-buffer buf)))) + +(defsubst ediff-background-face (buf-type dif-num) + ;; The value of dif-num is always 1- the one that user sees. + ;; This is why even face is used when dif-num is odd. + (ediff-get-symbol-from-alist + buf-type (if (ediff-odd-p dif-num) + ediff-even-diff-face-alist + ediff-odd-diff-face-alist) + )) + + +;; activate faces on diff regions in buffer +(defun ediff-paint-background-regions-in-one-buffer (buf-type unhighlight) + (let ((diff-vector + (eval (ediff-get-symbol-from-alist + buf-type ediff-difference-vector-alist))) + overl diff-num) + (mapcar (lambda (rec) + (setq overl (ediff-get-diff-overlay-from-diff-record rec) + diff-num (ediff-overlay-get overl 'ediff-diff-num)) + (if (ediff-overlay-buffer overl) + ;; only if overlay is alive + (ediff-set-overlay-face + overl + (if (not unhighlight) + (ediff-background-face buf-type diff-num)))) + ) + diff-vector))) + + +;; activate faces on diff regions in all buffers +(defun ediff-paint-background-regions (&optional unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'A unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'B unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'C unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'Ancestor unhighlight)) + + +;; arg is a record for a given diff in a difference vector +;; this record is itself a vector +(defsubst ediff-clear-fine-diff-vector (diff-record) + (if diff-record + (mapcar 'ediff-delete-overlay + (ediff-get-fine-diff-vector-from-diff-record diff-record)))) + +(defsubst ediff-clear-fine-differences-in-one-buffer (n buf-type) + (ediff-clear-fine-diff-vector (ediff-get-difference n buf-type)) + (ediff-set-fine-diff-vector n buf-type nil)) + +(defsubst ediff-clear-fine-differences (n) + (ediff-clear-fine-differences-in-one-buffer n 'A) + (ediff-clear-fine-differences-in-one-buffer n 'B) + (if ediff-3way-job + (ediff-clear-fine-differences-in-one-buffer n 'C))) + + +(defsubst ediff-mouse-event-p (event) + (ediff-cond-compile-for-xemacs-or-emacs + (button-event-p event) ; xemacs form + (string-match "mouse" (format "%S" (event-basic-type event))) ; emacs form + )) + + +(defsubst ediff-key-press-event-p (event) + (ediff-cond-compile-for-xemacs-or-emacs + (key-press-event-p event) ; xemacs form + (or (char-or-string-p event) (symbolp event)) ; emacs form + )) + +(defun ediff-event-point (event) + (cond ((ediff-mouse-event-p event) + (ediff-cond-compile-for-xemacs-or-emacs + (event-point event) ; xemacs form + (posn-point (event-start event)) ; emacs form + ) + ) + ((ediff-key-press-event-p event) + (point)) + (t (error nil)))) + +(defun ediff-event-buffer (event) + (cond ((ediff-mouse-event-p event) + (ediff-cond-compile-for-xemacs-or-emacs + (event-buffer event) ; xemacs form + (window-buffer (posn-window (event-start event))) ; emacs form + ) + ) + ((ediff-key-press-event-p event) + (current-buffer)) + (t (error nil)))) + +(defun ediff-event-key (event-or-key) + (ediff-cond-compile-for-xemacs-or-emacs + (if (eventp event-or-key) (event-key event-or-key) event-or-key) ; xemacs + event-or-key ; emacs form + )) + + +(defsubst ediff-frame-iconified-p (frame) + (if (and (ediff-window-display-p) (frame-live-p frame)) + (ediff-cond-compile-for-xemacs-or-emacs + (frame-iconified-p frame) ; xemacs form + (eq (frame-visible-p frame) 'icon) ; emacs form + ) + )) + +(defsubst ediff-window-visible-p (wind) + ;; under TTY, window-live-p also means window is visible + (and (window-live-p wind) + (or (not (ediff-window-display-p)) + (frame-visible-p (window-frame wind))))) + + +(defsubst ediff-frame-char-width (frame) + (ediff-cond-compile-for-xemacs-or-emacs + (/ (frame-pixel-width frame) (frame-width frame)) ; xemacs + (frame-char-width frame) ; emacs + )) + +(defun ediff-reset-mouse (&optional frame do-not-grab-mouse) + (or frame (setq frame (selected-frame))) + (if (ediff-window-display-p) + (let ((frame-or-wind frame)) + (if ediff-xemacs-p + (setq frame-or-wind (frame-selected-window frame))) + (or do-not-grab-mouse + ;; don't set mouse if the user said to never do this + (not ediff-grab-mouse) + ;; Don't grab on quit, if the user doesn't want to. + ;; If ediff-grab-mouse = t, then mouse won't be grabbed for + ;; sessions that are not part of a group (this is done in + ;; ediff-recenter). The condition below affects only terminating + ;; sessions in session groups (in which case mouse is warped into + ;; a meta buffer). + (and (eq ediff-grab-mouse 'maybe) + (memq this-command '(ediff-quit ediff-update-diffs))) + (set-mouse-position frame-or-wind 1 0)) + ))) + +(defsubst ediff-spy-after-mouse () + (setq ediff-mouse-pixel-position (mouse-pixel-position))) + +;; It is not easy to find out when the user grabs the mouse, since emacs and +;; xemacs behave differently when mouse is not in any frame. Also, this is +;; sensitive to when the user grabbed mouse. Not used for now. +(defun ediff-user-grabbed-mouse () + (if ediff-mouse-pixel-position + (cond ((not (eq (car ediff-mouse-pixel-position) + (car (mouse-pixel-position))))) + ((and (car (cdr ediff-mouse-pixel-position)) + (car (cdr (mouse-pixel-position))) + (cdr (cdr ediff-mouse-pixel-position)) + (cdr (cdr (mouse-pixel-position)))) + (not (and (< (abs (- (car (cdr ediff-mouse-pixel-position)) + (car (cdr (mouse-pixel-position))))) + ediff-mouse-pixel-threshold) + (< (abs (- (cdr (cdr ediff-mouse-pixel-position)) + (cdr (cdr (mouse-pixel-position))))) + ediff-mouse-pixel-threshold)))) + (t nil)))) + +(defsubst ediff-frame-char-height (frame) + (ediff-cond-compile-for-xemacs-or-emacs + (glyph-height ediff-H-glyph (frame-selected-window frame)) ; xemacs case + (frame-char-height frame) ; emacs case + ) + ) + +;; Some overlay functions + +(defsubst ediff-overlay-start (overl) + (if (ediff-overlayp overl) + (ediff-cond-compile-for-xemacs-or-emacs + (extent-start-position overl) ; xemacs form + (overlay-start overl) ; emacs form + ) + )) + +(defsubst ediff-overlay-end (overl) + (if (ediff-overlayp overl) + (ediff-cond-compile-for-xemacs-or-emacs + (extent-end-position overl) ; xemacs form + (overlay-end overl) ; emacs form + ) + )) + +(defsubst ediff-empty-overlay-p (overl) + (= (ediff-overlay-start overl) (ediff-overlay-end overl))) + +;; like overlay-buffer in Emacs. In XEmacs, returns nil if the extent is +;; dead. Otherwise, works like extent-buffer +(defun ediff-overlay-buffer (overl) + (ediff-cond-compile-for-xemacs-or-emacs + (and (extent-live-p overl) (extent-object overl)) ; xemacs form + (overlay-buffer overl) ; emacs form + )) + +;; like overlay-get in Emacs. In XEmacs, returns nil if the extent is +;; dead. Otherwise, like extent-property +(defun ediff-overlay-get (overl property) + (ediff-cond-compile-for-xemacs-or-emacs + (and (extent-live-p overl) (extent-property overl property)) ; xemacs form + (overlay-get overl property) ; emacs form + )) + + +;; These two functions are here because XEmacs refuses to +;; handle overlays whose buffers were deleted. +(defun ediff-move-overlay (overlay beg end &optional buffer) + "Calls `move-overlay' in Emacs and `set-extent-endpoints' in Lemacs. +Checks if overlay's buffer exists before actually doing the move." + (let ((buf (and overlay (ediff-overlay-buffer overlay)))) + (if (ediff-buffer-live-p buf) + (ediff-cond-compile-for-xemacs-or-emacs + (set-extent-endpoints overlay beg end) ; xemacs form + (move-overlay overlay beg end buffer) ; emacs form + ) + ;; buffer's dead + (if overlay + (ediff-delete-overlay overlay))))) + +(defun ediff-overlay-put (overlay prop value) + "Calls `overlay-put' or `set-extent-property' depending on Emacs version. +Checks if overlay's buffer exists." + (if (ediff-buffer-live-p (ediff-overlay-buffer overlay)) + (ediff-cond-compile-for-xemacs-or-emacs + (set-extent-property overlay prop value) ; xemacs form + (overlay-put overlay prop value) ; emacs form + ) + (ediff-delete-overlay overlay))) + +;; temporarily uses DIR to abbreviate file name +;; if DIR is nil, use default-directory +(defun ediff-abbreviate-file-name (file &optional dir) + (cond ((stringp dir) + (let ((directory-abbrev-alist (list (cons dir "")))) + (abbreviate-file-name file))) + (t + (ediff-cond-compile-for-xemacs-or-emacs + ;; XEmacs requires addl argument + (abbreviate-file-name file t) ; xemacs form + (abbreviate-file-name file)) ; emacs form + ) + )) + +;; Takes a directory and returns the parent directory. +;; does nothing to `/'. If the ARG is a regular file, +;; strip the file AND the last dir. +(defun ediff-strip-last-dir (dir) + (if (not (stringp dir)) (setq dir default-directory)) + (setq dir (expand-file-name dir)) + (or (file-directory-p dir) (setq dir (file-name-directory dir))) + (let* ((pos (1- (length dir))) + (last-char (aref dir pos))) + (if (and (> pos 0) (= last-char ?/)) + (setq dir (substring dir 0 pos))) + (ediff-abbreviate-file-name (file-name-directory dir)))) + +(defun ediff-truncate-string-left (str newlen) + ;; leave space for ... on the left + (let ((len (length str)) + substr) + (if (<= len newlen) + str + (setq newlen (max 0 (- newlen 3))) + (setq substr (substring str (max 0 (- len 1 newlen)))) + (concat "..." substr)))) + +(defsubst ediff-nonempty-string-p (string) + (and (stringp string) (not (string= string "")))) + +(unless (fboundp 'subst-char-in-string) + (defun subst-char-in-string (fromchar tochar string &optional inplace) + "Replace FROMCHAR with TOCHAR in STRING each time it occurs. +Unless optional argument INPLACE is non-nil, return a new string." + (let ((i (length string)) + (newstr (if inplace string (copy-sequence string)))) + (while (> i 0) + (setq i (1- i)) + (if (eq (aref newstr i) fromchar) + (aset newstr i tochar))) + newstr))) + +(defun ediff-abbrev-jobname (jobname) + (cond ((eq jobname 'ediff-directories) + "Compare two directories") + ((eq jobname 'ediff-files) + "Compare two files") + ((eq jobname 'ediff-buffers) + "Compare two buffers") + ((eq jobname 'ediff-directories3) + "Compare three directories") + ((eq jobname 'ediff-files3) + "Compare three files") + ((eq jobname 'ediff-buffers3) + "Compare three buffers") + ((eq jobname 'ediff-revision) + "Compare file with a version") + ((eq jobname 'ediff-directory-revisions) + "Compare dir files with versions") + ((eq jobname 'ediff-merge-directory-revisions) + "Merge dir files with versions") + ((eq jobname 'ediff-merge-directory-revisions-with-ancestor) + "Merge dir versions via ancestors") + (t + (capitalize + (subst-char-in-string ?- ?\s (substring (symbol-name jobname) 6)))) + )) + + +;; If ediff modified mode line, strip the modification +(defsubst ediff-strip-mode-line-format () + (if (member (car mode-line-format) '(" A: " " B: " " C: " " Ancestor: ")) + (setq mode-line-format (nth 2 mode-line-format)))) + +;; Verify that we have a difference selected. +(defsubst ediff-valid-difference-p (&optional n) + (or n (setq n ediff-current-difference)) + (and (>= n 0) (< n ediff-number-of-differences))) + +(defsubst ediff-show-all-diffs (n) + "Don't skip difference regions." + nil) + +(defsubst Xor (a b) + (or (and a (not b)) (and (not a) b))) + +(defsubst ediff-message-if-verbose (string &rest args) + (if ediff-verbose-p + (apply 'message string args))) + +(defun ediff-file-attributes (filename attr-number) + (if (ediff-listable-file filename) + (nth attr-number (file-attributes filename)) + -1) + ) + +(defsubst ediff-file-size (filename) + (ediff-file-attributes filename 7)) +(defsubst ediff-file-modtime (filename) + (ediff-file-attributes filename 5)) + + +(defun ediff-convert-standard-filename (fname) + (if (fboundp 'convert-standard-filename) + (convert-standard-filename fname) + fname)) + + +(if (fboundp 'with-syntax-table) + (defalias 'ediff-with-syntax-table 'with-syntax-table) + ;; stolen from subr.el in emacs 21 + (defmacro ediff-with-syntax-table (table &rest body) + (let ((old-table (make-symbol "table")) + (old-buffer (make-symbol "buffer"))) + `(let ((,old-table (syntax-table)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn + (set-syntax-table (copy-syntax-table ,table)) + ,@body) + (save-current-buffer + (set-buffer ,old-buffer) + (set-syntax-table ,old-table))))))) + + +(provide 'ediff-init) + + + +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) +;;; End: + +;;; arch-tag: fa31d384-1e70-4d4b-82a7-3e96307c46f5 +;;; ediff-init.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-init.elc b/xemacs-packages/lisp/ediff/ediff-init.elc new file mode 100644 index 0000000000000000000000000000000000000000..cfc2f2bc5395599c8821d74bf775081c4bfa8b44 GIT binary patch literal 63784 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 YT}@u^r^ap}OSD#b3QmEnBK;@+Ka*yZg#Z8m literal 0 HcmV?d00001 diff --git a/xemacs-packages/lisp/ediff/ediff-merg.el b/xemacs-packages/lisp/ediff/ediff-merg.el new file mode 100644 index 00000000..92f462c0 --- /dev/null +++ b/xemacs-packages/lisp/ediff/ediff-merg.el @@ -0,0 +1,402 @@ +;;; ediff-merg.el --- merging utilities + +;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +;; 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +;; Author: Michael Kifer + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;;; Code: + + +;; compiler pacifier +(defvar ediff-window-A) +(defvar ediff-window-B) +(defvar ediff-window-C) +(defvar ediff-merge-window-share) +(defvar ediff-window-config-saved) + +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + (or (featurep 'ediff-util) + (load "ediff-util.el" nil nil 'nosuffix)) + )) +;; end pacifier + +(require 'ediff-init) + +(defcustom ediff-quit-merge-hook 'ediff-maybe-save-and-delete-merge + "*Hooks to run before quitting a merge job. +The most common use is to save and delete the merge buffer." + :type 'hook + :group 'ediff-merge) + + +(defcustom ediff-default-variant 'combined + "*The variant to be used as a default for buffer C in merging. +Valid values are the symbols `default-A', `default-B', and `combined'." + :type '(radio (const default-A) (const default-B) (const combined)) + :group 'ediff-merge) + +(defcustom ediff-combination-pattern + '("<<<<<<< variant A" A ">>>>>>> variant B" B "####### Ancestor" Ancestor "======= end") + "*Pattern to be used for combining difference regions in buffers A and B. +The value must be a list of the form +(STRING1 bufspec1 STRING2 bufspec2 STRING3 bufspec3 STRING4) +where bufspec is the symbol A, B, or Ancestor. For instance, if the value is +'(STRING1 A STRING2 Ancestor STRING3 B STRING4) then the +combined text will look like this: + +STRING1 +diff region from variant A +STRING2 +diff region from the ancestor +STRING3 +diff region from variant B +STRING4 +" + :type '(choice (list string symbol string symbol string) + (list string symbol string symbol string symbol string)) + :group 'ediff-merge) + +(defcustom ediff-show-clashes-only nil + "*If t, show only those diff regions where both buffers disagree with the ancestor. +This means that regions that have status prefer-A or prefer-B will be +skipped over. nil means show all regions." + :type 'boolean + :group 'ediff-merge + ) +(make-variable-buffer-local 'ediff-show-clashes-only) + +(defcustom ediff-skip-merge-regions-that-differ-from-default nil + "*If t, show only the regions that have not been changed by the user. +A region is considered to have been changed if it is different from the current +default (`default-A', `default-B', `combined') and it hasn't been marked as +`prefer-A' or `prefer-B'. +A region is considered to have been changed also when it is marked as +as `prefer-A', but is different from the corresponding difference region in +Buffer A or if it is marked as `prefer-B' and is different from the region in +Buffer B." + :type 'boolean + :group 'ediff-merge + ) +(make-variable-buffer-local 'ediff-skip-merge-regions-that-differ-from-default) + +;; check if there is no clash between the ancestor and one of the variants. +;; if it is not a merge job then return true +(defsubst ediff-merge-region-is-non-clash (n) + (if (ediff-merge-job) + (string-match "prefer" (or (ediff-get-state-of-merge n) "")) + t)) + +;; If ediff-show-clashes-only, check if there is no clash between the ancestor +;; and one of the variants. +(defsubst ediff-merge-region-is-non-clash-to-skip (n) + (and ediff-show-clashes-only + (ediff-merge-region-is-non-clash n))) + +;; If ediff-skip-changed-regions, check if the merge region differs from +;; the current default. If a region is different from the default, it means +;; that the user has made determination as to how to merge for this particular +;; region. +(defsubst ediff-skip-merge-region-if-changed-from-default-p (n) + (and ediff-skip-merge-regions-that-differ-from-default + (ediff-merge-changed-from-default-p n 'prefers-too))) + + +(defun ediff-get-combined-region (n) + (let ((pattern-list ediff-combination-pattern) + (combo-region "") + (err-msg + "ediff-combination-pattern: Invalid format. Please consult the documentation") + region-delim region-spec) + + (if (< (length pattern-list) 5) + (error err-msg)) + + (while (> (length pattern-list) 2) + (setq region-delim (nth 0 pattern-list) + region-spec (nth 1 pattern-list)) + (or (and (stringp region-delim) (memq region-spec '(A B Ancestor))) + (error err-msg)) + + (condition-case nil + (setq combo-region + (concat combo-region + region-delim "\n" + (ediff-get-region-contents + n region-spec ediff-control-buffer))) + (error "")) + (setq pattern-list (cdr (cdr pattern-list))) + ) + + (setq region-delim (nth 0 pattern-list)) + (or (stringp region-delim) + (error err-msg)) + (setq combo-region (concat combo-region region-delim "\n")) + )) + +;;(defsubst ediff-make-combined-diff (regA regB) +;; (concat (nth 0 ediff-combination-pattern) "\n" +;; regA +;; (nth 1 ediff-combination-pattern) "\n" +;; regB +;; (nth 2 ediff-combination-pattern) "\n")) + +(defsubst ediff-set-state-of-all-diffs-in-all-buffers (ctl-buf) + (let ((n 0)) + (while (< n ediff-number-of-differences) + (ediff-set-state-of-diff-in-all-buffers n ctl-buf) + (setq n (1+ n))))) + +(defun ediff-set-state-of-diff-in-all-buffers (n ctl-buf) + (let ((regA (ediff-get-region-contents n 'A ctl-buf)) + (regB (ediff-get-region-contents n 'B ctl-buf)) + (regC (ediff-get-region-contents n 'C ctl-buf))) + (cond ((and (string= regA regB) (string= regA regC)) + (ediff-set-state-of-diff n 'A "=diff(B)") + (ediff-set-state-of-diff n 'B "=diff(C)") + (ediff-set-state-of-diff n 'C "=diff(A)")) + ((string= regA regB) + (ediff-set-state-of-diff n 'A "=diff(B)") + (ediff-set-state-of-diff n 'B "=diff(A)") + (ediff-set-state-of-diff n 'C nil)) + ((string= regA regC) + (ediff-set-state-of-diff n 'A "=diff(C)") + (ediff-set-state-of-diff n 'C "=diff(A)") + (ediff-set-state-of-diff n 'B nil)) + ((string= regB regC) + (ediff-set-state-of-diff n 'C "=diff(B)") + (ediff-set-state-of-diff n 'B "=diff(C)") + (ediff-set-state-of-diff n 'A nil)) + ((string= regC (ediff-get-combined-region n)) + (ediff-set-state-of-diff n 'A nil) + (ediff-set-state-of-diff n 'B nil) + (ediff-set-state-of-diff n 'C "=diff(A+B)")) + (t (ediff-set-state-of-diff n 'A nil) + (ediff-set-state-of-diff n 'B nil) + (ediff-set-state-of-diff n 'C nil))) + )) + +(defun ediff-set-merge-mode () + (normal-mode t) + (remove-hook 'local-write-file-hooks 'ediff-set-merge-mode)) + + +;; Go over all diffs starting with DIFF-NUM and copy regions into buffer C +;; according to the state of the difference. +;; Since ediff-copy-diff refuses to copy identical diff regions, there is +;; no need to optimize ediff-do-merge any further. +;; +;; If re-merging, change state of merge in all diffs starting with +;; DIFF-NUM, except those where the state is prefer-* or where it is +;; `default-*' or `combined' but the buf C region appears to be modified +;; since last set by default. +(defun ediff-do-merge (diff-num &optional remerging) + (if (< diff-num 0) (setq diff-num 0)) + (let ((n diff-num) + ;;(default-state-of-merge (format "%S" ediff-default-variant)) + do-not-copy state-of-merge) + (while (< n ediff-number-of-differences) + (setq do-not-copy nil) ; reset after each cycle + (if (= (mod n 10) 0) + (message "%s buffers A & B into C ... region %d of %d" + (if remerging "Re-merging" "Merging") + n + ediff-number-of-differences)) + + (setq state-of-merge (ediff-get-state-of-merge n)) + + (if remerging + ;;(let ((reg-A (ediff-get-region-contents n 'A ediff-control-buffer)) + ;; (reg-B (ediff-get-region-contents n 'B ediff-control-buffer)) + ;; (reg-C (ediff-get-region-contents n 'C ediff-control-buffer))) + (let () + + ;; if region was edited since it was first set by default + (if (or (ediff-merge-changed-from-default-p n) + ;; was preferred + (string-match "prefer" state-of-merge)) + ;; then ignore + (setq do-not-copy t)) + + ;; change state of merge for this diff, if necessary + (if (and (string-match "\\(default\\|combined\\)" state-of-merge) + (not do-not-copy)) + (ediff-set-state-of-merge + n (format "%S" ediff-default-variant))) + )) + + ;; state-of-merge may have changed via ediff-set-state-of-merge, so + ;; check it once again + (setq state-of-merge (ediff-get-state-of-merge n)) + + (or do-not-copy + (if (string= state-of-merge "combined") + ;; use n+1 because ediff-combine-diffs works via user numbering + ;; of diffs, which is 1+ to what ediff uses internally + (ediff-combine-diffs (1+ n) 'batch) + (ediff-copy-diff + n (if (string-match "-A" state-of-merge) 'A 'B) 'C 'batch))) + (setq n (1+ n))) + (message "Merging buffers A & B into C ... Done") + )) + + +(defun ediff-re-merge () + "Remerge unmodified diff regions using a new default. Start with the current region." + (interactive) + (let* ((default-variant-alist + (list '("default-A") '("default-B") '("combined"))) + (actual-alist + (delete (list (symbol-name ediff-default-variant)) + default-variant-alist))) + (setq ediff-default-variant + (intern + (completing-read + (format "Current merge default is `%S'. New default: " + ediff-default-variant) + actual-alist nil 'must-match))) + (ediff-do-merge ediff-current-difference 'remerge) + (ediff-recenter) + )) + +(defun ediff-shrink-window-C (arg) + "Shrink window C to just one line. +With a prefix argument, returns window C to its normal size. +Used only for merging jobs." + (interactive "P") + (if (not ediff-merge-job) + (error "ediff-shrink-window-C can be used only for merging jobs")) + (cond ((eq arg '-) (setq arg -1)) + ((not (numberp arg)) (setq arg nil))) + (cond ((null arg) + (let ((ediff-merge-window-share + (if (< (window-height ediff-window-C) 3) + ediff-merge-window-share 0))) + (setq ediff-window-config-saved "") ; force redisplay + (ediff-recenter 'no-rehighlight))) + ((and (< arg 0) (> (window-height ediff-window-C) 2)) + (setq ediff-merge-window-share (* ediff-merge-window-share 0.9)) + (setq ediff-window-config-saved "") ; force redisplay + (ediff-recenter 'no-rehighlight)) + ((and (> arg 0) (> (window-height ediff-window-A) 2)) + (setq ediff-merge-window-share (* ediff-merge-window-share 1.1)) + (setq ediff-window-config-saved "") ; force redisplay + (ediff-recenter 'no-rehighlight)))) + + +;; N here is the user's region number. It is 1+ what Ediff uses internally. +(defun ediff-combine-diffs (n &optional batch-invocation) + "Combine Nth diff regions of buffers A and B and place the combination in C. +N is a prefix argument. If nil, combine the current difference regions. +Combining is done according to the specifications in variable +`ediff-combination-pattern'." + (interactive "P") + (setq n (if (numberp n) (1- n) ediff-current-difference)) + + (let (reg-combined) + ;;(setq regA (ediff-get-region-contents n 'A ediff-control-buffer) + ;; regB (ediff-get-region-contents n 'B ediff-control-buffer)) + ;;(setq reg-combined (ediff-make-combined-diff regA regB)) + (setq reg-combined (ediff-get-combined-region n)) + + (ediff-copy-diff n nil 'C batch-invocation reg-combined)) + (or batch-invocation (ediff-jump-to-difference (1+ n)))) + + +;; Checks if the region in buff C looks like a combination of the regions +;; in buffers A and B. Return a list (reg-a-beg reg-a-end reg-b-beg reg-b-end) +;; These refer to where the delimiters for region A, B, Ancestor start and end +;; in buffer C +(defun ediff-looks-like-combined-merge (region-num) + (if ediff-merge-job + (let ((combined (string-match (regexp-quote "(A+B)") + (or (ediff-get-state-of-diff region-num 'C) + ""))) + (mrgreg-beg (ediff-get-diff-posn 'C 'beg region-num)) + (mrgreg-end (ediff-get-diff-posn 'C 'end region-num)) + (pattern-list ediff-combination-pattern) + delim reg-beg reg-end delim-regs-list) + + (if combined + (ediff-with-current-buffer ediff-buffer-C + (while pattern-list + (goto-char mrgreg-beg) + (setq delim (nth 0 pattern-list)) + (search-forward delim mrgreg-end 'noerror) + (setq reg-beg (match-beginning 0)) + (setq reg-end (match-end 0)) + (if (and reg-beg reg-end) + (setq delim-regs-list + ;; in reverse + (cons reg-end (cons reg-beg delim-regs-list)))) + (if (> (length pattern-list) 1) + (setq pattern-list (cdr (cdr pattern-list))) + (setq pattern-list nil)) + ))) + + (reverse delim-regs-list) + ))) + +(eval-when-compile (defvar state-of-merge)) ; dynamic var + +;; Check if the non-preferred merge has been modified since originally set. +;; This affects only the regions that are marked as default-A/B or combined. +;; If PREFERS-TOO is non-nil, then look at the regions marked as prefers-A/B as +;; well. +(defun ediff-merge-changed-from-default-p (diff-num &optional prefers-too) + (let ((reg-A (ediff-get-region-contents diff-num 'A ediff-control-buffer)) + (reg-B (ediff-get-region-contents diff-num 'B ediff-control-buffer)) + (reg-C (ediff-get-region-contents diff-num 'C ediff-control-buffer))) + + (setq state-of-merge (ediff-get-state-of-merge diff-num)) + + ;; if region was edited since it was first set by default + (or (and (string= state-of-merge "default-A") + (not (string= reg-A reg-C))) + (and (string= state-of-merge "default-B") + (not (string= reg-B reg-C))) + (and (string= state-of-merge "combined") + ;;(not (string= (ediff-make-combined-diff reg-A reg-B) reg-C))) + (not (string= (ediff-get-combined-region diff-num) reg-C))) + (and prefers-too + (string= state-of-merge "prefer-A") + (not (string= reg-A reg-C))) + (and prefers-too + (string= state-of-merge "prefer-B") + (not (string= reg-B reg-C))) + ))) + + +(provide 'ediff-merg) + + +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) +;;; End: + +;;; arch-tag: 9b798cf9-02ba-487f-a62e-b63aa823dbfb +;;; ediff-merg.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-merg.elc b/xemacs-packages/lisp/ediff/ediff-merg.elc new file mode 100644 index 0000000000000000000000000000000000000000..cf98bfa56a063c638279c634928e2d91e3a1ba26 GIT binary patch literal 9249 zcmeHM+iw)t8K+Vo*4~SRAyqKooE<~FOPIxL2n5p$yABt(lu{s2iA800_t-n}?#wbX z3pnZvgp0RPb5Sp%QX^GWrKnyz4^{e9sUiVvgTV%J@8wVEdmsDz&N;Ied!0bkhdk5| z>zOm>eCNBJ-*-8C_8l5pyK2>{&OLkfu$)~gn?;^y*>Pr#?Je3lqgb$AFCm`tcF8a; zW?SqertIfgHZZ`F+XtWDF*uN91O5Fw1(6ZQF0m1iVcQCJiEp#Uww1?5^=!o~=C^s= z^|oE$B_rqRWg|CcjBef$XEec!f|8iV&T+>zvFSiEv4h3RhLAQm;&Kd^b9Ns8&lgOvlDC;yv^jiQ=6dEM_}Prjm2$ zV|{A8WQ=FI?i%N~4rO9_k$YTDWZIU4nCddmW=_RoSq@n^BT63B!wg3L#M#SsHj%N8 z7dR`yok{W%Oblz1nX#6LGqRK<&ODkaR%RE7sFJ4r~0-wUeb6WfzS9%^fhFRIY!>JSuAH;P*#08?A|(( zu8;Uc;&JwsbR*Y`g9ljfJnmS~PfYu^{Hv=brLh##zAOLgqiKz$nbs@+Sjx%)WNZgh z)f3acBmWq;@*0q1%MrClld4I(k_~bkGAxJN=QwltDDc1~jZ5vj;DJ<^RxTy<&Ps4@ zvYWx^j4*pd7y(pE87p?|_|f6R2a-gvSu$z58LO|(O{&3$zq-ywy1qXxx9BHh z`DSJwzu>X+X0gbMbW)4v82Oy(4rZ*3rG(8`q(r4YCZdAx;VFO8K$}U#EwN5E^yh7F zGtVcM_9yMgSoLEX%N1-B#)}DKNU-!(*6t0S{FpOaseDz3cMJA;9Wdw?xU1V%ah&x5 zJmHzcFxOT_pAmjA>>>Vg;f{4jRPJDV1@Z~Fsf+KfG3sy*n_#qAgThAvawTrShrNQ~ z)#-?r0wEuK#jCii>~K)iQ{+zSIW4W6h4I}nvs?xy*$7PuMp&W&W4fCI<&)CAXmmp3ts@t5|a7Ks&7``DBUN;ZmURX{bq9M|Dj_( zzL&ve$&^JC8fs1$bjhG@y1Hds5(`-GshEZM)N#|Ty>aVy#;RS*Sb>8x2j9Ioo6)Y# zUDMbpi^;45DUEI!C9YoS2y@*YQF&3UDK*h4b#>J|k*ui0);cC;=>#B1vn2esTk{1o z9DdHERK1mMeYACD9H=8w*pkTTHR+)m>t~wAywhyQX=sk}cb&3rrrmh|@CWYHm7BM2 zWVDIfH{PG=C2cf|*-oK?fXeGRl3GG7MO2hJNKK1K!E}D1jF28@DqY@;G^*%uBR@_j z3NgKv&Q_K)=$H|LiK8HhXsiscUzs{&dJ<>QJzFOU zHvuM1P_m4SyK>BIK5#4SBu_GE*!F3*{RxioGCsaQoUgxeM!5&*k``W?f2omYs0C%U7@<-wKCd8lfW=a%+Wfi$`L_a2 z!un8uaT~f>$ShkW~_}H?uNn{Ew$zQ!GrVnh9~Bh4Ba1| zxU*zvVfd2sjR=u>90Ci=2`owi?Ko(=-7=;GfdJOOx0JW`5-gQ-ad`6I9S?$05Lo`H z&2Gz7@NjtY&tGlj;_!2Hz;P(kbcBbL!#9qBevaqR2*4Smu8L^E=%N!R2Ua}SC?3*i zlNqjS=h$|1fQV!)9S5e#$Dzh!3XhZ+Hi${U<9Q!A)tc0EL;!rIe76F8tb`RZ(=Ji+ z+IvbA_cz{;PJD3lmI}TEn?+rGr<%Nkx?1)tc>pV_Xt@STh{^HS~g zyYrEr+N<{_FWwIaHcbSluLQ#=M%H5Rj|<`G)YZiYp^R3$^ssC35k0(>v8G-R)?TAo zAAS^hCZi2E7UA35p^vZECO!!t{}gCA`Q~Tg#m{NktAC%o_>X^nx@jVO91-rDcmEX? zJ|V5q9vbUHK~favh_mH!A1hl6p*msPKbRn=At&b7>!h?>=_A?4ty!=q=(vLCHI4h(^?MogHVJ9Qv4FYE-^E2Q3 zG8uTA46oqu820kN_?xMB8H!j|R8mrJq!BU9G+lH}=`{Gft}N?|w#CWAm4o=lQT8JI z*0l_fy?bBS$&QMd=z>^qWOKwszkzI{bmpQvLRG%OEPmc^B%^n9%rhM7AF5uJ>UpR| ziD#C_UfdQ)`>B(3>-NmP?%BCubO;ScZQY%_^Y?-ot>gZ}rs$f*zyr9~L$;+Ub5K_p z#G2~r8ac0m<0nx>^;&%S)TmVCl5Z@g`6DT`k{fSn@m4ob9OBYFg=!bdQXNi3oo!4i z;~O*sd@=kCifKcVP0`p#&rdag&?h>x`B)#+cDSL$K_(%Ky3V?+pcT9R(U&&#+XD{I zA=}{&Ovhrqn^=PF+?CuNC)fji_3lj$>|n`(7AueL;}G?(UZ$otTml_lizhly zlEnu7mlzixeJb<9npj%4D3joyx=>v%fVxl7Xxc9v~yJmv7W;-(0=81U6yO-yJ$D?0}MN0`15Y|ga zge(eJlK*x!r7xL}_kIrba-~$JUPc4-8i#+^uKs@C=F18ly3%n`0-`&w^pLNkFK%`z z80rYiSRZ-j%G4^W<7$u~+bmJeN8$tdTFPOmXX*a{q?S;QCFmgP zXDc=kUyI2+k&Gp$t5YL`KvPochjE%oX41>HOUEA=0dC0bE;pQ9K?h=VzWOeA^-GkLN^Ve%v1L5o6d-uKIJv?^M)!6dI=do0j-zvrQvH x6)eE;Mt;$F#ufLn + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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: + +;; Users are encouraged to add functionality to this file. +;; The present file contains all the infrastructure needed for that. +;; +;; Generally, to implement a new multisession capability within Ediff, +;; you need to tell it +;; +;; 1. How to display the session group buffer. +;; This function must indicate which Ediff sessions are active (+) and +;; which are finished (-). +;; See ediff-redraw-directory-group-buffer for an example. +;; In all likelihood, ediff-redraw-directory-group-buffer can be used +;; directly or after a small modification. +;; 2. What action to take when the user clicks button 2 or types v,e, or +;; RET. See ediff-filegroup-action. +;; 3. Provide a list of pairs or triples of file names (or buffers, +;; depending on the particular Ediff operation you want to invoke) +;; in the following format: +;; (HEADER (nil nil (obj1 nil) (obj2 nil) (obj3 nil)) +;; (...) ...) +;; The function ediff-make-new-meta-list-element can be used to create +;; 2nd and subsequent elements of that list (i.e., after the +;; description header). See ediff-make-new-meta-list-element for the +;; explanation of the two nil placeholders in such elements. +;; +;; There is API for extracting the components of the members of the +;; above list. Search for `API for ediff-meta-list' for details. +;; +;; HEADER must be a list of SIX elements (nil or string): +;; (regexp metaobj1 metaobj2 metaobj3 merge-save-buffer +;; comparison-function) +;; The function ediff-redraw-registry-buffer displays the +;; 1st - 4th of these in the registry buffer. +;; For some jobs some of the members of the header might be nil. +;; The meaning of metaobj1, metaobj2, and metaobj3 depend on the job. +;; Typically these are directories where the files to be compared are +;; found. +;; Also, keep in mind that the function ediff-prepare-meta-buffer +;; (which see) prepends the session group buffer to the descriptor, so +;; the descriptor becomes 7-long. +;; Ediff expects that your function (in 2 above) will arrange to +;; replace this prepended nil (via setcar) with the actual ediff +;; control buffer associated with an appropriate Ediff session. +;; This is arranged through internal startup hooks that can be passed +;; to any of Ediff major entries (such as ediff-files, epatch, etc.). +;; See how this is done in ediff-filegroup-action. +;; +;; Session descriptions are of the form +;; (nil nil (obj1 . nil) (obj2 . nil) (obj3 . nil)) +;; which describe the objects relevant to the session. +;; Use ediff-make-new-meta-list-element to create these things. +;; Usually obj1/2/3 are names of files, but they may also be other +;; things for some jobs. For instance, obj3 is nil for jobs that +;; involve only two files. For patch jobs, obj2 and obj3 are markers +;; that specify the patch corresponding to the file +;; (whose name is obj1). +;; The nil's are placeholders, which are used internally by ediff. +;; 4. Write a function that makes a call to ediff-prepare-meta-buffer +;; passing all this info. +;; You may be able to use ediff-directories-internal as a template. +;; 5. If you intend to add several related pieces of functionality, +;; you may want to keep the function in 4 as an internal version +;; and then write several top-level interactive functions that call it +;; with different parameters. +;; See how ediff-directories, ediff-merge-directories, and +;; ediff-merge-directories-with-ancestor all use +;; ediff-directories-internal. +;; +;; A useful addition here could be session groups selected by patterns +;; (which are different in each directory). For instance, one may want to +;; compare files of the form abc{something}.c to files old{something}.d +;; which may be in the same or different directories. Or, one may want to +;; compare all files of the form {something} to files of the form {something}~. +;; +;; Implementing this requires writing a collating function, which should pair +;; up appropriate files. It will also require a generalization of the +;; functions that do the layout of the meta- and differences buffers and of +;; ediff-filegroup-action. + +;;; Code: + + +(defgroup ediff-mult nil + "Multi-file and multi-buffer processing in Ediff." + :prefix "ediff-" + :group 'ediff) + + +;; compiler pacifier +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + (or (featurep 'ediff-util) + (load "ediff-util.el" nil nil 'nosuffix)) + )) +;; end pacifier + +(require 'ediff-init) + +;; meta-buffer +(ediff-defvar-local ediff-meta-buffer nil "") +(ediff-defvar-local ediff-parent-meta-buffer nil "") +;; the registry buffer +(defvar ediff-registry-buffer nil) + +(defconst ediff-meta-buffer-message "This is an Ediff Session Group Panel: %s + +Useful commands: + button2, v, or RET over session record: start that Ediff session + M:\tin sessions invoked from here, brings back this group panel + R:\tdisplay the registry of active Ediff sessions + h:\tmark session for hiding (toggle) + x:\thide marked sessions; with prefix arg: unhide + m:\tmark session for a non-hiding operation (toggle) + uh/um:\tunmark all sessions marked for hiding/operation + n,SPC:\tnext session + p,DEL:\tprevious session + E:\tbrowse Ediff on-line manual + T:\ttoggle truncation of long file names + q:\tquit this session group +") + +(ediff-defvar-local ediff-meta-buffer-map nil + "The keymap for the meta buffer.") +(defvar ediff-dir-diffs-buffer-map (make-sparse-keymap) + "The keymap to be installed in the buffer showing differences between +directories.") + +;; Variable specifying the action to take when the use invokes ediff in the +;; meta buffer. This is usually ediff-registry-action or ediff-filegroup-action +(ediff-defvar-local ediff-meta-action-function nil "") +;; Tells ediff-update-meta-buffer how to redraw it +(ediff-defvar-local ediff-meta-redraw-function nil "") +;; Tells ediff-filegroup-action and similar procedures how to invoke Ediff for +;; the sessions in a given session group +(ediff-defvar-local ediff-session-action-function nil "") + +(ediff-defvar-local ediff-metajob-name nil "") + +;; buffer used to collect custom diffs from individual sessions in the group +(ediff-defvar-local ediff-meta-diff-buffer nil "") + +;; t means recurse into subdirs when deciding which files have same contents +(ediff-defvar-local ediff-recurse-to-subdirectories nil "") + +;; history var to use for filtering groups of files +(defvar ediff-filtering-regexp-history nil "") + +(defcustom ediff-default-filtering-regexp nil + "The default regular expression used as a filename filter in multifile comparisons. +Should be a sexp. For instance (car ediff-filtering-regexp-history) or nil." + :type 'sexp + :group 'ediff-mult) + +;; This has the form ((meta-buf regexp dir1 dir2 dir3 merge-auto-store-dir) +;; (ctl-buf session-status (file1 . eq-status) (file2 . eq-status) (file3 +;; . eq-status)) (ctl-buf session-status (file1 . eq-status) (file2 +;; . eq-status)) ...) +;; If ctl-buf is nil, the file-pair hasn't processed yet. If it is +;; killed-buffer object, the file pair has been processed. If it is a live +;; buffer, this means ediff is still working on the pair. +;; Eq-status of a file is t if the file equals some other file in the same +;; group. +(ediff-defvar-local ediff-meta-list nil "") + +(ediff-defvar-local ediff-meta-session-number nil "") + + +;; the difference list between directories in a directory session group +(ediff-defvar-local ediff-dir-difference-list nil "") +(ediff-defvar-local ediff-dir-diffs-buffer nil "") + +;; The registry of Ediff sessions. A list of control buffers. +(defvar ediff-session-registry nil) + +(defcustom ediff-meta-truncate-filenames t + "*If non-nil, truncate long file names in the session group buffers. +This can be toggled with `ediff-toggle-filename-truncation'." + :type 'boolean + :group 'ediff-mult) + +(defcustom ediff-meta-mode-hook nil + "*Hooks run just after setting up meta mode." + :type 'hook + :group 'ediff-mult) + +(defcustom ediff-registry-setup-hook nil + "*Hooks run just after the registry control panel is set up." + :type 'hook + :group 'ediff-mult) + +(defcustom ediff-before-session-group-setup-hooks nil + "*Hooks to run before Ediff arranges the window for group-level operations. +It is used by commands such as `ediff-directories'. +This hook can be used to save the previous window config, which can be restored +on `ediff-quit', `ediff-suspend', or `ediff-quit-session-group-hook'." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-after-session-group-setup-hook nil + "*Hooks run just after a meta-buffer controlling a session group, such as +ediff-directories, is run." + :type 'hook + :group 'ediff-mult) +(defcustom ediff-quit-session-group-hook nil + "*Hooks run just before exiting a session group." + :type 'hook + :group 'ediff-mult) +(defcustom ediff-show-registry-hook nil + "*Hooks run just after the registry buffer is shown." + :type 'hook + :group 'ediff-mult) +(defcustom ediff-show-session-group-hook '(delete-other-windows) + "*Hooks run just after a session group buffer is shown." + :type 'hook + :group 'ediff-mult) +(defcustom ediff-meta-buffer-keymap-setup-hook nil + "*Hooks run just after setting up the `ediff-meta-buffer-map'. +This keymap controls key bindings in the meta buffer and is a local variable. +This means that you can set different bindings for different kinds of meta +buffers." + :type 'hook + :group 'ediff-mult) + +;; Buffer holding the multi-file patch. Local to the meta buffer +(ediff-defvar-local ediff-meta-patchbufer nil "") + +;;; API for ediff-meta-list + +;; A meta-list is either ediff-meta-list, which contains a header and the list +;; of ediff sessions or ediff-dir-difference-list, which is a header followed +;; by the list of differences among the directories (i.e., files that are not +;; in all directories). The header is the same in all meta lists, but the rest +;; is different. +;; Structure of the meta-list: +;; (HEADER SESSION1 SESSION2 ...) +;; HEADER: (GROUP-BUF REGEXP OBJA OBJB OBJC SAVE-DIR COMPARISON-FUNC) +;; OBJA - first directory +;; OBJB - second directory +;; OBJC - third directory +;; SESSION1/2/... are described below +;; group buffer/regexp +(defsubst ediff-get-group-buffer (meta-list) + (nth 0 (car meta-list))) + +(defsubst ediff-get-group-regexp (meta-list) + (nth 1 (car meta-list))) +;; group objects +(defsubst ediff-get-group-objA (meta-list) + (nth 2 (car meta-list))) +(defsubst ediff-get-group-objB (meta-list) + (nth 3 (car meta-list))) +(defsubst ediff-get-group-objC (meta-list) + (nth 4 (car meta-list))) +(defsubst ediff-get-group-merge-autostore-dir (meta-list) + (nth 5 (car meta-list))) +(defsubst ediff-get-group-comparison-func (meta-list) + (nth 6 (car meta-list))) + +;; ELT is a session meta descriptor (what is being preserved as +;; 'ediff-meta-info) +;; The structure is: (SESSION-CTL-BUFFER STATUS OBJA OBJB OBJC) +;; STATUS is ?I (hidden or invalid), ?* (marked for operation), ?H (hidden) +;; nil (nothing) +;; OBJA/B/C is (FILENAME EQSTATUS) +;; EQSTATUS is ?= or nil (?= means that this file is equal to some other +;; file in this session) +;; session buffer +(defsubst ediff-get-session-buffer (elt) + (nth 0 elt)) +(defsubst ediff-get-session-status (elt) + (nth 1 elt)) +(defsubst ediff-set-session-status (session-info new-status) + (setcar (cdr session-info) new-status)) +;; session objects +(defsubst ediff-get-session-objA (elt) + (nth 2 elt)) +(defsubst ediff-get-session-objB (elt) + (nth 3 elt)) +(defsubst ediff-get-session-objC (elt) + (nth 4 elt)) +;; Take the "name" component of the object into acount. ObjA/C/B is of the form +;; (name . equality-indicator) +(defsubst ediff-get-session-objA-name (elt) + (car (nth 2 elt))) +(defsubst ediff-get-session-objB-name (elt) + (car (nth 3 elt))) +(defsubst ediff-get-session-objC-name (elt) + (car (nth 4 elt))) +;; equality indicators +(defsubst ediff-get-file-eqstatus (elt) + (nth 1 elt)) +(defsubst ediff-set-file-eqstatus (elt value) + (setcar (cdr elt) value)) + +;; Create a new element for the meta list out of obj1/2/3, which usually are +;; files +;; +;; The first nil in such an element is later replaced with the session buffer. +;; The second nil is reserved for session status. +;; +;; Also, session objects A/B/C are turned into lists of the form (obj nil). +;; This nil is a placeholder for eq-indicator. It is either nil or =. +;; If it is discovered that this file is = to some other +;; file in the same session, eq-indicator is changed to `='. +;; Curently, the eq-indicator is used only for 2 and 3-file jobs. +(defun ediff-make-new-meta-list-element (obj1 obj2 obj3) + (list nil nil (list obj1 nil) (list obj2 nil) (list obj3 nil))) + +;; Constructs a meta list header. +;; OBJA, OBJB, OBJC are usually directories involved, but can be different for +;; different jobs. For instance, multifile patch has only OBJA, which is the +;; patch buffer. +(defun ediff-make-new-meta-list-header (regexp + objA objB objC + merge-auto-store-dir + comparison-func) + (list regexp objA objB objC merge-auto-store-dir comparison-func)) + +;; The activity marker is either or + (active session, i.e., ediff is currently +;; run in it), or - (finished session, i.e., we've ran ediff in it and then +;; exited). Return nil, if session is neither active nor finished +(defun ediff-get-session-activity-marker (session) + (let ((session-buf (ediff-get-session-buffer session))) + (cond ((null session-buf) nil) ; virgin session + ((ediff-buffer-live-p session-buf) ?+) ;active session + (t ?-)))) + +;; checks if the session is a meta session +(defun ediff-meta-session-p (session-info) + (and (stringp (ediff-get-session-objA-name session-info)) + (file-directory-p (ediff-get-session-objA-name session-info)) + (stringp (ediff-get-session-objB-name session-info)) + (file-directory-p (ediff-get-session-objB-name session-info)) + (if (stringp (ediff-get-session-objC-name session-info)) + (file-directory-p (ediff-get-session-objC-name session-info)) t))) + +;; set up the keymap in the meta buffer +(defun ediff-setup-meta-map () + (setq ediff-meta-buffer-map (make-sparse-keymap)) + (suppress-keymap ediff-meta-buffer-map) + (define-key ediff-meta-buffer-map "q" 'ediff-quit-meta-buffer) + (define-key ediff-meta-buffer-map "T" 'ediff-toggle-filename-truncation) + (define-key ediff-meta-buffer-map "R" 'ediff-show-registry) + (define-key ediff-meta-buffer-map "E" 'ediff-documentation) + (define-key ediff-meta-buffer-map "v" ediff-meta-action-function) + (define-key ediff-meta-buffer-map "\C-m" ediff-meta-action-function) + (define-key ediff-meta-buffer-map " " 'ediff-next-meta-item) + (define-key ediff-meta-buffer-map "n" 'ediff-next-meta-item) + (define-key ediff-meta-buffer-map "\C-?" 'ediff-previous-meta-item) + (define-key ediff-meta-buffer-map "p" 'ediff-previous-meta-item) + (define-key ediff-meta-buffer-map [delete] 'ediff-previous-meta-item) + (define-key ediff-meta-buffer-map [backspace] 'ediff-previous-meta-item) + (or (ediff-one-filegroup-metajob) + (progn + (define-key ediff-meta-buffer-map "=" nil) + (define-key ediff-meta-buffer-map "==" 'ediff-meta-mark-equal-files) + (define-key ediff-meta-buffer-map "=m" 'ediff-meta-mark-equal-files) + (define-key ediff-meta-buffer-map "=h" 'ediff-meta-mark-equal-files))) + (if ediff-no-emacs-help-in-control-buffer + (define-key ediff-meta-buffer-map "\C-h" 'ediff-previous-meta-item)) + (if ediff-emacs-p + (define-key ediff-meta-buffer-map [mouse-2] ediff-meta-action-function) + (define-key ediff-meta-buffer-map [button2] ediff-meta-action-function)) + + (use-local-map ediff-meta-buffer-map) + ;; modify ediff-meta-buffer-map here + (run-hooks 'ediff-meta-buffer-keymap-setup-hook)) + + +(defun ediff-meta-mode () + "This mode controls all operations on Ediff session groups. +It is entered through one of the following commands: + `ediff-directories' + `edirs' + `ediff-directories3' + `edirs3' + `ediff-merge-directories' + `edirs-merge' + `ediff-merge-directories-with-ancestor' + `edirs-merge-with-ancestor' + `ediff-directory-revisions' + `edir-revisions' + `ediff-merge-directory-revisions' + `edir-merge-revisions' + `ediff-merge-directory-revisions-with-ancestor' + `edir-merge-revisions-with-ancestor' + +Commands: +\\{ediff-meta-buffer-map}" + (kill-all-local-variables) + (setq major-mode 'ediff-meta-mode) + (setq mode-name "MetaEdiff") + ;; don't use run-mode-hooks here! + (run-hooks 'ediff-meta-mode-hook)) + + +;; the keymap for the buffer showing directory differences +(suppress-keymap ediff-dir-diffs-buffer-map) +(define-key ediff-dir-diffs-buffer-map "q" 'ediff-bury-dir-diffs-buffer) +(define-key ediff-dir-diffs-buffer-map " " 'next-line) +(define-key ediff-dir-diffs-buffer-map "n" 'next-line) +(define-key ediff-dir-diffs-buffer-map "\C-?" 'previous-line) +(define-key ediff-dir-diffs-buffer-map "p" 'previous-line) +(define-key ediff-dir-diffs-buffer-map "C" 'ediff-dir-diff-copy-file) +(if ediff-emacs-p + (define-key ediff-dir-diffs-buffer-map [mouse-2] 'ediff-dir-diff-copy-file) + (define-key ediff-dir-diffs-buffer-map [button2] 'ediff-dir-diff-copy-file)) +(define-key ediff-dir-diffs-buffer-map [delete] 'previous-line) +(define-key ediff-dir-diffs-buffer-map [backspace] 'previous-line) + +(defun ediff-next-meta-item (count) + "Move to the next item in Ediff registry or session group buffer. +Moves in circular fashion. With numeric prefix arg, skip this many items." + (interactive "p") + (or count (setq count 1)) + (let (overl) + (while (< 0 count) + (setq count (1- count)) + (ediff-next-meta-item1) + (setq overl (ediff-get-meta-overlay-at-pos (point))) + ;; skip invisible ones + (while (and overl (ediff-overlay-get overl 'invisible)) + (ediff-next-meta-item1) + (setq overl (ediff-get-meta-overlay-at-pos (point))))))) + +;; Move to the next meta item +(defun ediff-next-meta-item1 () + (let (pos) + (setq pos (ediff-next-meta-overlay-start (point))) + (if pos (goto-char pos)) + (if (eq ediff-metajob-name 'ediff-registry) + (if (and (ediff-get-meta-info (current-buffer) pos 'noerror) + (search-forward "*Ediff" nil t)) + (skip-chars-backward "a-zA-Z*")) + (if (> (skip-chars-forward "-+?H* \t0-9") 0) + (backward-char 1))))) + + +(defun ediff-previous-meta-item (count) + "Move to the previous item in Ediff registry or session group buffer. +Moves in circular fashion. With numeric prefix arg, skip this many items." + (interactive "p") + (or count (setq count 1)) + (let (overl) + (while (< 0 count) + (setq count (1- count)) + (ediff-previous-meta-item1) + (setq overl (ediff-get-meta-overlay-at-pos (point))) + ;; skip invisible ones + (while (and overl (ediff-overlay-get overl 'invisible)) + (ediff-previous-meta-item1) + (setq overl (ediff-get-meta-overlay-at-pos (point))))))) + +(defun ediff-previous-meta-item1 () + (let (pos) + (setq pos (ediff-previous-meta-overlay-start (point))) +;;; ;; skip deleted +;;; (while (ediff-get-session-status +;;; (ediff-get-meta-info (current-buffer) pos 'noerror)) +;;; (setq pos (ediff-previous-meta-overlay-start pos))) + + (if pos (goto-char pos)) + (if (eq ediff-metajob-name 'ediff-registry) + (if (and (ediff-get-meta-info (current-buffer) pos 'noerror) + (search-forward "*Ediff" nil t)) + (skip-chars-backward "a-zA-Z*")) + (if (> (skip-chars-forward "-+?H* \t0-9") 0) + (backward-char 1))) + )) + +(defsubst ediff-add-slash-if-directory (dir file) + (if (file-directory-p (concat dir file)) + (file-name-as-directory file) + file)) + +(defun ediff-toggle-filename-truncation () + "Toggle truncation of long file names in session group buffers. +Set `ediff-meta-truncate-filenames' variable if you want to change the default +behavior." + (interactive) + (setq ediff-meta-truncate-filenames (not ediff-meta-truncate-filenames)) + (ediff-update-meta-buffer (current-buffer) 'must-redraw)) + + +;; These are used to encode membership of files in directory1/2/3 +;; Membership code of a file is a product of codes for the directories where +;; this file is in +(defvar ediff-membership-code1 2) +(defvar ediff-membership-code2 3) +(defvar ediff-membership-code3 5) +(defvar ediff-product-of-memcodes (* ediff-membership-code1 + ediff-membership-code2 + ediff-membership-code3)) + +;; DIR1, DIR2, DIR3 are directories. DIR3 can be nil. +;; OUTPUT-DIR is a directory for auto-storing the results of merge jobs. +;; Can be nil. +;; REGEXP is nil or a filter regexp; only file names that match the regexp +;; are considered. +;; If a file is a directory in dir1 but not dir2 (or vice versa), it is not +;; included in the intersection. However, a regular file that is a dir in dir3 +;; is included, since dir3 files are supposed to be ancestors for merging. +;; If COMPARISON-FUNC is given, use it. Otherwise, use string= +;; +;; Returns a list of the form: +;; (COMMON-PART DIFF-LIST) +;; COMMON-PART is car and DIFF-LIST is cdr. +;; +;; COMMON-PART is of the form: +;; (META-HEADER (f1 f2 f3) (f1 f2 f3) ...) +;; f3 can be nil if intersecting only 2 directories. +;; Each triple (f1 f2 f3) represents the files to be compared in the +;; corresponding ediff subsession. +;; +;; DIFF-LIST is of the form: +;; (META-HEADER (file . num) (file . num)...) +;; where num encodes the set of dirs where the file is found: +;; 2 - only dir1; 3 - only dir2; 5 - only dir3; 6 - dir1&2; 10 - dir1&3; etc. +;; META-HEADER: +;; Contains the meta info about this ediff operation +;; (regexp dir1 dir2 dir3 merge-auto-store-dir comparison-func) +;; Later the meta-buffer is prepended to this list. +;; +;; Some operations might use a different meta header. For instance, +;; ediff-multifile-patch doesn't have dir2 and dir3, and regexp, +;; comparison-func don't apply. +;; +(defun ediff-intersect-directories (jobname + regexp dir1 dir2 + &optional + dir3 merge-autostore-dir comparison-func) + (setq comparison-func (or comparison-func 'string=)) + (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 common-part difflist) + + (setq auxdir1 (file-name-as-directory dir1) + lis1 (directory-files auxdir1 nil regexp) + lis1 (delete "." lis1) + lis1 (delete ".." lis1) + lis1 (mapcar + (lambda (elt) + (ediff-add-slash-if-directory auxdir1 elt)) + lis1) + auxdir2 (file-name-as-directory dir2) + lis2 (directory-files auxdir2 nil regexp) + lis2 (delete "." lis2) + lis2 (delete ".." lis2) + lis2 (mapcar + (lambda (elt) + (ediff-add-slash-if-directory auxdir2 elt)) + lis2)) + + (if (stringp dir3) + (setq auxdir3 (file-name-as-directory dir3) + lis3 (directory-files auxdir3 nil regexp) + lis3 (delete "." lis3) + lis3 (delete ".." lis3) + lis3 (mapcar + (lambda (elt) + (ediff-add-slash-if-directory auxdir3 elt)) + lis3))) + + (if (ediff-nonempty-string-p merge-autostore-dir) + (setq merge-autostore-dir + (file-name-as-directory merge-autostore-dir))) + (setq common (ediff-intersection lis1 lis2 comparison-func)) + + ;; In merge with ancestor jobs, we don't intersect with lis3. + ;; If there is no ancestor, we'll offer to merge without the ancestor. + ;; So, we intersect with lis3 only when we are doing 3-way file comparison + (if (and lis3 (ediff-comparison-metajob3 jobname)) + (setq common (ediff-intersection common lis3 comparison-func))) + + ;; copying is needed because sort sorts via side effects + (setq common (sort (ediff-copy-list common) 'string-lessp)) + + ;; compute difference list + (setq difflist (ediff-set-difference + (ediff-union (ediff-union lis1 lis2 comparison-func) + lis3 + comparison-func) + common + comparison-func) + difflist (delete "." difflist) + ;; copying is needed because sort sorts via side effects + difflist (sort (ediff-copy-list (delete ".." difflist)) + 'string-lessp)) + + (setq difflist (mapcar (lambda (elt) (cons elt 1)) difflist)) + + ;; check for files belonging to lis1/2/3 + ;; Each elt is of the norm (file . number) + ;; Number encodes the directories to which file belongs. + ;; It is a product of a subset of ediff-membership-code1=2, + ;; ediff-membership-code2=3, and ediff-membership-code3=5. + ;; If file belongs to dir 1 only, the membership code is 2. + ;; If it is in dir1 and dir3, then the membership code is 2*5=10; + ;; if it is in dir1 and dir2, then the membership code is 2*3=6, etc. + (mapcar (lambda (elt) + (if (member (car elt) lis1) + (setcdr elt (* (cdr elt) ediff-membership-code1))) + (if (member (car elt) lis2) + (setcdr elt (* (cdr elt) ediff-membership-code2))) + (if (member (car elt) lis3) + (setcdr elt (* (cdr elt) ediff-membership-code3))) + ) + difflist) + (setq difflist (cons + ;; diff metalist header + (ediff-make-new-meta-list-header regexp + auxdir1 auxdir2 auxdir3 + merge-autostore-dir + comparison-func) + difflist)) + + (setq common-part + (cons + ;; metalist header + (ediff-make-new-meta-list-header regexp + auxdir1 auxdir2 auxdir3 + merge-autostore-dir + comparison-func) + (mapcar + (lambda (elt) + (ediff-make-new-meta-list-element + (concat auxdir1 elt) + (concat auxdir2 elt) + (if lis3 + (progn + ;; The following is done because: In merging with + ;; ancestor, we don't intersect with lis3. So, it is + ;; possible that elt is a file in auxdir1/2 but a + ;; directory in auxdir3 Or elt may not exist in auxdir3 at + ;; all. In the first case, we add a slash at the end. In + ;; the second case, we insert nil. + (setq elt (ediff-add-slash-if-directory auxdir3 elt)) + (if (file-exists-p (concat auxdir3 elt)) + (concat auxdir3 elt)))))) + common))) + ;; return result + (cons common-part difflist) + )) + +;; find directory files that are under revision. Include subdirectories, since +;; we may visit them recursively. DIR1 is the directory to inspect. +;; MERGE-AUTOSTORE-DIR is the directory where to auto-store the results of +;; merges. Can be nil. +(defun ediff-get-directory-files-under-revision (jobname + regexp dir1 + &optional merge-autostore-dir) + (let (lis1 elt common auxdir1) + (setq auxdir1 (file-name-as-directory dir1) + lis1 (directory-files auxdir1 nil regexp)) + + (if (ediff-nonempty-string-p merge-autostore-dir) + (setq merge-autostore-dir + (file-name-as-directory merge-autostore-dir))) + + (while lis1 + (setq elt (car lis1) + lis1 (cdr lis1)) + ;; take files under revision control + (cond ((file-directory-p (concat auxdir1 elt)) + (setq common + (cons (ediff-add-slash-if-directory auxdir1 elt) common))) + ((and (featurep 'vc-hooks) (vc-backend (concat auxdir1 elt))) + (setq common (cons elt common))) + ;; The following two are needed only if vc-hooks isn't loaded. + ;; They won't recognize CVS files. + ((file-exists-p (concat auxdir1 elt ",v")) + (setq common (cons elt common))) + ((file-exists-p (concat auxdir1 "RCS/" elt ",v")) + (setq common (cons elt common))) + ) ; cond + ) ; while + + (setq common (delete "./" common) + common (delete "../" common) + common (delete "RCS" common) + common (delete "CVS" common) + ) + + ;; copying is needed because sort sorts via side effects + (setq common (sort (ediff-copy-list common) 'string-lessp)) + + ;; return result + (cons + ;; header -- has 6 elements. Meta buffer is prepended later by + ;; ediff-prepare-meta-buffer + (ediff-make-new-meta-list-header regexp + auxdir1 nil nil + merge-autostore-dir nil) + (mapcar (lambda (elt) (ediff-make-new-meta-list-element + (concat auxdir1 elt) nil nil)) + common)) + )) + + +;; If file groups selected by patterns will ever be implemented, this +;; comparison function might become useful. +;;;; uses external variables PAT1 PAT2 to compare str1/2 +;;;; patterns must be of the form ???*???? where ??? are strings of chars +;;;; containing no *. +;;(defun ediff-pattern= (str1 str2) +;; (let (pos11 pos12 pos21 pos22 len1 len2) +;; (setq pos11 0 +;; len (length epat1) +;; pos12 len) +;; (while (and (< pos11 len) (not (= (aref epat1 pos11) ?*))) +;; (setq pos11 (1+ pos11))) +;; (while (and (> pos12 0) (not (= (aref epat1 (1- pos12)) ?*))) +;; (setq pos12 (1- pos12))) +;; +;; (setq pos21 0 +;; len (length epat2) +;; pos22 len) +;; (while (and (< pos21 len) (not (= (aref epat2 pos21) ?*))) +;; (setq pos21 (1+ pos21))) +;; (while (and (> pos22 0) (not (= (aref epat2 (1- pos22)) ?*))) +;; (setq pos22 (1- pos22))) +;; +;; (if (and (> (length str1) pos12) (>= pos12 pos11) (> pos11 -1) +;; (> (length str2) pos22) (>= pos22 pos21) (> pos21 -1)) +;; (string= (substring str1 pos11 pos12) +;; (substring str2 pos21 pos22))) +;; )) + + +;; Prepare meta-buffer in accordance with the argument-function and +;; redraw-function. Must return the created meta-buffer. +(defun ediff-prepare-meta-buffer (action-func meta-list + meta-buffer-name redraw-function + jobname &optional startup-hooks) + (let* ((meta-buffer-name + (ediff-unique-buffer-name meta-buffer-name "*")) + (meta-buffer (get-buffer-create meta-buffer-name))) + (ediff-with-current-buffer meta-buffer + + ;; comes first + (ediff-meta-mode) + + (setq ediff-meta-action-function action-func + ediff-meta-redraw-function redraw-function + ediff-metajob-name jobname + ediff-meta-buffer meta-buffer) + + ;; comes after ediff-meta-action-function is set + (ediff-setup-meta-map) + + (if (eq ediff-metajob-name 'ediff-registry) + (progn + (setq ediff-registry-buffer meta-buffer + ediff-meta-list meta-list) + ;; this func is used only from registry buffer, not from other + ;; meta-buffs. + (define-key + ediff-meta-buffer-map "M" 'ediff-show-meta-buff-from-registry)) + ;; Initialize the meta list -- we don't do this for registry. + (setq ediff-meta-list + ;; add meta-buffer to the list header + (cons (cons meta-buffer (car meta-list)) + (cdr meta-list)))) + + (or (eq meta-buffer ediff-registry-buffer) + (setq ediff-session-registry + (cons meta-buffer ediff-session-registry))) + + ;; redraw-function uses ediff-meta-list + (funcall redraw-function ediff-meta-list) + + ;; set read-only/non-modified + (setq buffer-read-only t) + (set-buffer-modified-p nil) + + (run-hooks 'startup-hooks) + + ;; Arrange to show directory contents differences + ;; Must be after run startup-hooks, since ediff-dir-difference-list is + ;; set inside these hooks + (if (eq action-func 'ediff-filegroup-action) + (progn + ;; put meta buffer in (car ediff-dir-difference-list) + (setq ediff-dir-difference-list + (cons (cons meta-buffer (car ediff-dir-difference-list)) + (cdr ediff-dir-difference-list))) + + (or (ediff-one-filegroup-metajob jobname) + (ediff-draw-dir-diffs ediff-dir-difference-list)) + (define-key + ediff-meta-buffer-map "h" 'ediff-mark-for-hiding-at-pos) + (define-key ediff-meta-buffer-map "x" 'ediff-hide-marked-sessions) + (define-key + ediff-meta-buffer-map "m" 'ediff-mark-for-operation-at-pos) + (define-key ediff-meta-buffer-map "u" nil) + (define-key + ediff-meta-buffer-map "um" 'ediff-unmark-all-for-operation) + (define-key + ediff-meta-buffer-map "uh" 'ediff-unmark-all-for-hiding) + (cond ((ediff-collect-diffs-metajob jobname) + (define-key + ediff-meta-buffer-map "P" 'ediff-collect-custom-diffs)) + ((ediff-patch-metajob jobname) + (define-key + ediff-meta-buffer-map "P" 'ediff-meta-show-patch))) + (define-key ediff-meta-buffer-map "^" 'ediff-up-meta-hierarchy) + (define-key ediff-meta-buffer-map "D" 'ediff-show-dir-diffs))) + + (if (eq ediff-metajob-name 'ediff-registry) + (run-hooks 'ediff-registry-setup-hook) + (run-hooks 'ediff-after-session-group-setup-hook)) + ) ; eval in meta-buffer + meta-buffer)) + +;; Insert the activity marker for session SESSION in the meta buffer at point +;; The activity marker is either SPC (untouched session), or + (active session, +;; i.e., ediff is currently run in it), or - (finished session, i.e., we've ran +;; ediff in it and then exited) +(defun ediff-insert-session-activity-marker-in-meta-buffer (session) + (insert + (cond ((ediff-get-session-activity-marker session)) + ;; virgin session + (t " ")))) + +;; Insert session status at point. Status is either ?H (marked for hiding), or +;; ?I (hidden or invalid), or ?* (meaning marked for an operation; currently, +;; such op can only be checking for equality)), or SPC (meaning neither marked +;; nor invalid) +(defun ediff-insert-session-status-in-meta-buffer (session) + (insert + (cond ((ediff-get-session-status session)) ; session has status: ?H, ?I, ?* + ;; normal session, no marks or hidings + (t " ")))) + +;; If NEW-MARKER is non-nil, use it to substitute the current activity marker +;; in the meta buffer. If nil, use SPC +(defun ediff-replace-session-activity-marker-in-meta-buffer (point new-marker) + (let* ((overl (ediff-get-meta-overlay-at-pos point)) + (session-info (ediff-overlay-get overl 'ediff-meta-info)) + (activity-marker (ediff-get-session-activity-marker session-info)) + buffer-read-only) + (or new-marker activity-marker (setq new-marker ?\s)) + (goto-char (ediff-overlay-start overl)) + (if (eq (char-after (point)) new-marker) + () ; if marker shown in buffer is the same as new-marker, do nothing + (insert new-marker) + (delete-char 1) + (set-buffer-modified-p nil)))) + +;; If NEW-STATUS is non-nil, use it to substitute the current status marker in +;; the meta buffer. If nil, use SPC +(defun ediff-replace-session-status-in-meta-buffer (point new-status) + (let* ((overl (ediff-get-meta-overlay-at-pos point)) + (session-info (ediff-overlay-get overl 'ediff-meta-info)) + (status (ediff-get-session-status session-info)) + buffer-read-only) + (setq new-status (or new-status status ?\s)) + (goto-char (ediff-overlay-start overl)) + (forward-char 1) ; status is the second char in session record + (if (eq (char-after (point)) new-status) + () ; if marker shown in buffer is the same as new-marker, do nothing + (insert new-status) + (delete-char 1) + (set-buffer-modified-p nil)))) + +;; insert all file info in meta buffer for a given session +(defun ediff-insert-session-info-in-meta-buffer (session-info sessionNum) + (let ((f1 (ediff-get-session-objA session-info)) + (f2 (ediff-get-session-objB session-info)) + (f3 (ediff-get-session-objC session-info)) + (pt (point)) + (hidden (eq (ediff-get-session-status session-info) ?I))) + ;; insert activity marker, i.e., SPC, - or + + (ediff-insert-session-activity-marker-in-meta-buffer session-info) + ;; insert session status, i.e., *, H + (ediff-insert-session-status-in-meta-buffer session-info) + (insert " Session " (int-to-string sessionNum) ":\n") + (ediff-meta-insert-file-info1 f1) + (ediff-meta-insert-file-info1 f2) + (ediff-meta-insert-file-info1 f3) + (ediff-set-meta-overlay pt (point) session-info sessionNum hidden))) + + +;; this is a setup function for ediff-directories +;; must return meta-buffer +(defun ediff-redraw-directory-group-buffer (meta-list) + ;; extract directories + (let ((meta-buf (ediff-get-group-buffer meta-list)) + (empty t) + (sessionNum 0) + regexp elt merge-autostore-dir + point tmp-list buffer-read-only) + (ediff-with-current-buffer meta-buf + (setq point (point)) + (erase-buffer) + ;; delete phony overlays that used to represent sessions before the buff + ;; was redrawn + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents 'delete-extent) ; xemacs + (mapcar 'delete-overlay (overlays-in 1 1)) ; emacs + ) + + (insert (format ediff-meta-buffer-message + (ediff-abbrev-jobname ediff-metajob-name))) + + (setq regexp (ediff-get-group-regexp meta-list) + merge-autostore-dir + (ediff-get-group-merge-autostore-dir meta-list)) + + (cond ((ediff-collect-diffs-metajob) + (insert + " P:\tcollect custom diffs of all marked sessions\n")) + ((ediff-patch-metajob) + (insert + " P:\tshow patch appropriately for the context (session or group)\n"))) + (insert + " ^:\tshow parent session group\n") + (or (ediff-one-filegroup-metajob) + (insert + " D:\tshow differences among directories\n" + " ==:\tfor each session, show which files are identical\n" + " =h:\tlike ==, but also marks those sessions for hiding\n" + " =m:\tlike ==, but also marks those sessions for operation\n\n")) + + (insert "\n") + (if (and (stringp regexp) (> (length regexp) 0)) + (insert + (format "*** Filter-through regular expression: %s\n" regexp))) + (ediff-insert-dirs-in-meta-buffer meta-list) + (if (and ediff-autostore-merges (ediff-merge-metajob) + (ediff-nonempty-string-p merge-autostore-dir)) + (insert (format + "\nMerge results are automatically stored in:\n\t%s\n" + merge-autostore-dir))) + (insert "\n + Size Last modified Name + ---------------------------------------------- + +") + + ;; discard info on directories and regexp + (setq meta-list (cdr meta-list) + tmp-list meta-list) + (while (and tmp-list empty) + (if (and (car tmp-list) + (not (eq (ediff-get-session-status (car tmp-list)) ?I))) + (setq empty nil)) + (setq tmp-list (cdr tmp-list))) + + (if empty + (insert + " ****** ****** This session group has no members\n")) + + ;; now organize file names like this: + ;; use-mark sizeA dateA sizeB dateB filename + ;; make sure directories are displayed with a trailing slash. + (while meta-list + (setq elt (car meta-list) + meta-list (cdr meta-list) + sessionNum (1+ sessionNum)) + (if (eq (ediff-get-session-status elt) ?I) + () + (ediff-insert-session-info-in-meta-buffer elt sessionNum))) + (set-buffer-modified-p nil) + (goto-char point) + meta-buf))) + +(defun ediff-update-markers-in-dir-meta-buffer (meta-list) + (let ((meta-buf (ediff-get-group-buffer meta-list)) + session-info point overl buffer-read-only) + (ediff-with-current-buffer meta-buf + (setq point (point)) + (goto-char (point-min)) + (ediff-next-meta-item1) + (while (not (bobp)) + (setq session-info (ediff-get-meta-info meta-buf (point) 'no-error) + overl (ediff-get-meta-overlay-at-pos (point))) + (if session-info + (progn + (cond ((eq (ediff-get-session-status session-info) ?I) + ;; Do hiding + (if overl (ediff-overlay-put overl 'invisible t))) + ((and (eq (ediff-get-session-status session-info) ?H) + overl (ediff-overlay-get overl 'invisible)) + ;; Do unhiding + (ediff-overlay-put overl 'invisible nil)) + (t (ediff-replace-session-activity-marker-in-meta-buffer + (point) + (ediff-get-session-activity-marker session-info)) + (ediff-replace-session-status-in-meta-buffer + (point) + (ediff-get-session-status session-info)))))) + (ediff-next-meta-item1) ; advance to the next item + ) ; end while + (set-buffer-modified-p nil) + (goto-char point)) + meta-buf)) + +(defun ediff-update-session-marker-in-dir-meta-buffer (session-num) + (let (buffer-meta-overlays session-info overl buffer-read-only) + (setq overl + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents ; xemacs + (lambda (ext maparg) + (if (and + (ediff-overlay-get ext 'ediff-meta-info) + (eq (ediff-overlay-get ext 'ediff-meta-session-number) + session-num)) + ext))) + ;; Emacs doesn't have map-extents, so try harder + ;; Splice overlay lists to get all buffer overlays + (progn + (setq buffer-meta-overlays (overlay-lists) + buffer-meta-overlays (append (car buffer-meta-overlays) + (cdr buffer-meta-overlays))) + (car + (delq nil + (mapcar + (lambda (overl) + (if (and + (ediff-overlay-get overl 'ediff-meta-info) + (eq (ediff-overlay-get + overl 'ediff-meta-session-number) + session-num)) + overl)) + buffer-meta-overlays)))) + )) + (or overl + (error + "Bug in ediff-update-session-marker-in-dir-meta-buffer: no overlay with given number %S" + session-num)) + (setq session-info (ediff-overlay-get overl 'ediff-meta-info)) + (goto-char (ediff-overlay-start overl)) + (ediff-replace-session-activity-marker-in-meta-buffer + (point) + (ediff-get-session-activity-marker session-info)) + (ediff-replace-session-status-in-meta-buffer + (point) + (ediff-get-session-status session-info))) + (ediff-next-meta-item1)) + + + +;; Check if this is a problematic session. +;; Return nil if not. Otherwise, return symbol representing the problem +;; At present, problematic sessions occur only in -with-ancestor comparisons +;; when the ancestor is a directory rather than a file, or when there is no +;; suitable ancestor file in the ancestor directory +(defun ediff-problematic-session-p (session) + (let ((f1 (ediff-get-session-objA-name session)) + (f2 (ediff-get-session-objB-name session)) + (f3 (ediff-get-session-objC-name session))) + (cond ((and (stringp f1) (not (file-directory-p f1)) + (stringp f2) (not (file-directory-p f2)) + ;; either invalid file name or a directory + (or (not (stringp f3)) (file-directory-p f3)) + (ediff-ancestor-metajob)) + ;; more may be added later + 'ancestor-is-dir) + (t nil)))) + +(defun ediff-meta-insert-file-info1 (fileinfo) + (let ((fname (car fileinfo)) + (feq (ediff-get-file-eqstatus fileinfo)) + (max-filename-width (if ediff-meta-truncate-filenames + (- (window-width) 41) + 500)) + file-modtime file-size) + (cond ((not (stringp fname)) (setq file-size -2)) ; file doesn't exits + ((ediff-listable-file fname) + (if (file-exists-p fname) + ;; set real size and modtime + (setq file-size (ediff-file-size fname) + file-modtime (ediff-file-modtime fname)) + (setq file-size -2))) ; file doesn't exist + ( t (setq file-size -1))) ; remote file + (if (stringp fname) + (insert + (format + "%s %s %-20s %s\n" + (if feq "=" " ") ; equality indicator + (format "%10s" (cond ((= file-size -1) "--") + ((< file-size -1) "--") + (t file-size))) + (cond ((= file-size -1) "*remote file*") + ((< file-size -1) "*file doesn't exist*") + (t (ediff-format-date (decode-time file-modtime)))) + + ;; dir names in meta lists have training slashes, so we just + ;; abbreviate the file name, if file exists + (if (and (not (stringp fname)) (< file-size -1)) + "-------" ; file doesn't exist + (ediff-truncate-string-left + (ediff-abbreviate-file-name fname) + max-filename-width))))))) + +(defconst ediff-months '((1 . "Jan") (2 . "Feb") (3 . "Mar") (4 . "Apr") + (5 . "May") (6 . "Jun") (7 . "Jul") (8 . "Aug") + (9 . "Sep") (10 . "Oct") (11 . "Nov") (12 . "Dec")) + "Months' associative array.") + +;; returns 2char string +(defsubst ediff-fill-leading-zero (num) + (if (< num 10) + (format "0%d" num) + (number-to-string num))) + +;; TIME is like the output of decode-time +(defun ediff-format-date (time) + (format "%s %2d %4d %s:%s:%s" + (cdr (assoc (nth 4 time) ediff-months)) ; month + (nth 3 time) ; day + (nth 5 time) ; year + (ediff-fill-leading-zero (nth 2 time)) ; hour + (ediff-fill-leading-zero (nth 1 time)) ; min + (ediff-fill-leading-zero (nth 0 time)) ; sec + )) + +;; Draw the directories +(defun ediff-insert-dirs-in-meta-buffer (meta-list) + (let* ((dir1 (ediff-abbreviate-file-name (ediff-get-group-objA meta-list))) + (dir2 (ediff-get-group-objB meta-list)) + (dir2 (if (stringp dir2) (ediff-abbreviate-file-name dir2))) + (dir3 (ediff-get-group-objC meta-list)) + (dir3 (if (stringp dir3) (ediff-abbreviate-file-name dir3)))) + (insert "*** Directory A: " dir1 "\n") + (if dir2 (insert "*** Directory B: " dir2 "\n")) + (if dir3 (insert "*** Directory C: " dir3 "\n")) + (insert "\n"))) + +(defun ediff-draw-dir-diffs (diff-list &optional buf-name) + (if (null diff-list) (error "Lost difference info on these directories")) + (setq buf-name + (or buf-name + (ediff-unique-buffer-name "*Ediff File Group Differences" "*"))) + (let* ((regexp (ediff-get-group-regexp diff-list)) + (dir1 (ediff-abbreviate-file-name (ediff-get-group-objA diff-list))) + (dir2 (ediff-abbreviate-file-name (ediff-get-group-objB diff-list))) + (dir3 (ediff-get-group-objC diff-list)) + (dir3 (if (stringp dir3) (ediff-abbreviate-file-name dir3))) + (meta-buf (ediff-get-group-buffer diff-list)) + (underline (make-string 26 ?-)) + file membership-code saved-point + buffer-read-only) + ;; skip the directory part + (setq diff-list (cdr diff-list)) + (setq ediff-dir-diffs-buffer (get-buffer-create buf-name)) + (ediff-with-current-buffer ediff-dir-diffs-buffer + (setq saved-point (point)) + (use-local-map ediff-dir-diffs-buffer-map) + (erase-buffer) + (setq ediff-meta-buffer meta-buf) + (insert "\t\t*** Directory Differences ***\n") + (insert " +Useful commands: + C,button2: over file name -- copy this file to directory that doesn't have it + q: hide this buffer + n,SPC: next line + p,DEL: previous line\n\n") + + (insert (format "\n*** Directory A: %s\n" dir1)) + (if dir2 (insert (format "*** Directory B: %s\n" dir2))) + (if dir3 (insert (format "*** Directory C: %s\n" dir3))) + (if (and (stringp regexp) (> (length regexp) 0)) + (insert + (format "*** Filter-through regular expression: %s\n" regexp))) + (insert "\n") + (insert (format "\n%-27s%-26s" "Directory A" "Directory B")) + (if dir3 + (insert (format " %-25s\n" "Directory C")) + (insert "\n")) + (insert (format "%s%s" underline underline)) + (if (stringp dir3) + (insert (format "%s\n\n" underline)) + (insert "\n\n")) + + (if (null diff-list) + (insert "\n\t*** No differences ***\n")) + + (while diff-list + (setq file (car (car diff-list)) + membership-code (cdr (car diff-list)) + diff-list (cdr diff-list)) + (if (= (mod membership-code ediff-membership-code1) 0) ; dir1 + (let ((beg (point))) + (insert (format "%-27s" + (ediff-truncate-string-left + (ediff-abbreviate-file-name + (if (file-directory-p (concat dir1 file)) + (file-name-as-directory file) + file)) + 24))) + ;; format of meta info in the dir-diff-buffer: + ;; (filename-tail filename-full otherdir1 otherdir2 otherdir3) + (ediff-set-meta-overlay + beg (point) + (list meta-buf file (concat dir1 file) dir1 dir2 dir3))) + (insert (format "%-27s" "---"))) + (if (= (mod membership-code ediff-membership-code2) 0) ; dir2 + (let ((beg (point))) + (insert (format "%-26s" + (ediff-truncate-string-left + (ediff-abbreviate-file-name + (if (file-directory-p (concat dir2 file)) + (file-name-as-directory file) + file)) + 24))) + (ediff-set-meta-overlay + beg (point) + (list meta-buf file (concat dir2 file) dir1 dir2 dir3))) + (insert (format "%-26s" "---"))) + (if (stringp dir3) + (if (= (mod membership-code ediff-membership-code3) 0) ; dir3 + (let ((beg (point))) + (insert (format " %-25s" + (ediff-truncate-string-left + (ediff-abbreviate-file-name + (if (file-directory-p (concat dir3 file)) + (file-name-as-directory file) + file)) + 24))) + (ediff-set-meta-overlay + beg (point) + (list meta-buf file (concat dir3 file) dir1 dir2 dir3))) + (insert (format " %-25s" "---")))) + (insert "\n")) + (setq buffer-read-only t) + (set-buffer-modified-p nil) + (goto-char saved-point)) ; end eval in diff buffer + )) + +(defun ediff-bury-dir-diffs-buffer () + "Bury the directory difference buffer. Display the meta buffer instead." + (interactive) + ;; ediff-meta-buffer is set in ediff-draw-dir-diffs so the directory + ;; difference buffer remembers the meta buffer + (let ((buf ediff-meta-buffer) + wind) + (ediff-kill-buffer-carefully ediff-dir-diffs-buffer) + (if (setq wind (ediff-get-visible-buffer-window buf)) + (select-window wind) + (set-window-buffer (selected-window) buf)))) + +;; executes in dir session group buffer +;; show buffer differences +(defun ediff-show-dir-diffs () + "Display differences among the directories involved in session group." + (interactive) + (if (ediff-one-filegroup-metajob) + (error "This command is inapplicable in the present context")) + (or (ediff-buffer-live-p ediff-dir-diffs-buffer) + (ediff-draw-dir-diffs ediff-dir-difference-list)) + (let ((buf ediff-dir-diffs-buffer)) + (other-window 1) + (set-window-buffer (selected-window) buf) + (goto-char (point-min)))) + +;; Format of meta info in dir-diff-buffer: +;; (filename-tail filename-full otherdir1 otherdir2) +(defun ediff-dir-diff-copy-file () + "Copy file described at point to directories where this file is missing." + (interactive) + (let* ((pos (ediff-event-point last-command-event)) + (info (ediff-get-meta-info (current-buffer) pos 'noerror)) + (meta-buf (car info)) + (file-tail (nth 1 info)) + (file-abs (nth 2 info)) + (otherdir1 (nth 3 info)) + (otherfile1 (if otherdir1 (concat otherdir1 file-tail))) + (otherdir2 (nth 4 info)) + (otherfile2 (if otherdir2 (concat otherdir2 file-tail))) + (otherdir3 (nth 5 info)) + (otherfile3 (if otherdir3 (concat otherdir3 file-tail))) + meta-list dir-diff-list + ) + (if (null info) + (error "No file suitable for copying described at this location")) + (ediff-with-current-buffer meta-buf + (setq meta-list ediff-meta-list + dir-diff-list ediff-dir-difference-list)) + + ;; copy file to directories where it doesn't exist, update + ;; ediff-dir-difference-list and redisplay + (mapcar + (lambda (otherfile-struct) + (let ((otherfile (car otherfile-struct)) + (file-mem-code (cdr otherfile-struct))) + (if otherfile + (or (file-exists-p otherfile) + (if (y-or-n-p + (format "Copy %s to %s? " file-abs otherfile)) + (let* ((file-diff-record (assoc file-tail dir-diff-list)) + (new-mem-code + (* (cdr file-diff-record) file-mem-code))) + (copy-file file-abs otherfile) + (setcdr file-diff-record new-mem-code) + (ediff-draw-dir-diffs dir-diff-list (buffer-name)) + (sit-for 0) + ;; if file is in all three dirs or in two dirs and only + ;; two dirs are involved, delete this file's record + (if (or (= new-mem-code ediff-product-of-memcodes) + (and (> new-mem-code ediff-membership-code3) + (null otherfile3))) + (delq file-diff-record dir-diff-list)) + )))) + )) + ;; 2,3,5 are numbers used to encode membership of a file in + ;; dir1/2/3. See ediff-intersect-directories. + (list (cons otherfile1 2) (cons otherfile2 3) (cons otherfile3 5))) + + (if (and (file-exists-p otherfile1) + (file-exists-p otherfile2) + (or (not otherfile3) (file-exists-p otherfile3))) + ;; update ediff-meta-list by direct modification + (nconc meta-list + (list (ediff-make-new-meta-list-element + otherfile1 otherfile2 otherfile3))) + ) + (ediff-update-meta-buffer meta-buf 'must-redraw) + )) + +(defun ediff-up-meta-hierarchy () + "Go to the parent session group buffer." + (interactive) + (if (ediff-buffer-live-p ediff-parent-meta-buffer) + (ediff-show-meta-buffer + ediff-parent-meta-buffer ediff-meta-session-number) + (error "This session group has no parent"))) + + +;; argument is ignored +(defun ediff-redraw-registry-buffer (&optional ignore) + (ediff-with-current-buffer ediff-registry-buffer + (let ((point (point)) + elt bufAname bufBname bufCname cur-diff total-diffs pt + job-name meta-list registry-list buffer-read-only) + (erase-buffer) + ;; delete phony overlays that used to represent sessions before the buff + ;; was redrawn + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents 'delete-extent) ; xemacs + (mapcar 'delete-overlay (overlays-in 1 1)) ; emacs + ) + + (insert "This is a registry of all active Ediff sessions. + +Useful commands: + button2, `v', RET over a session record: switch to that session + M over a session record: display the associated session group + R in any Ediff session: display session registry + n,SPC: next session + p,DEL: previous session + E: browse Ediff on-line manual + q: bury registry + + +\t\tActive Ediff Sessions: +\t\t---------------------- + +") + ;; purge registry list from dead buffers + (mapcar (lambda (elt) + (if (not (ediff-buffer-live-p elt)) + (setq ediff-session-registry + (delq elt ediff-session-registry)))) + ediff-session-registry) + + (if (null ediff-session-registry) + (insert " ******* No active Ediff sessions *******\n")) + + (setq registry-list ediff-session-registry) + (while registry-list + (setq elt (car registry-list) + registry-list (cdr registry-list)) + + (if (ediff-buffer-live-p elt) + (if (ediff-with-current-buffer elt + (setq job-name ediff-metajob-name + meta-list ediff-meta-list) + (and ediff-metajob-name + (not (eq ediff-metajob-name 'ediff-registry)))) + (progn + (setq pt (point)) + (insert (format " *group*\t%s: %s\n" + (buffer-name elt) + (ediff-abbrev-jobname job-name))) + (insert (format "\t\t %s %s %s\n" + (ediff-abbreviate-file-name + (ediff-get-group-objA meta-list)) + (ediff-abbreviate-file-name + (if (stringp + (ediff-get-group-objB meta-list)) + (ediff-get-group-objB meta-list) + "")) + (ediff-abbreviate-file-name + (if (stringp + (ediff-get-group-objC meta-list)) + (ediff-get-group-objC meta-list) + "")))) + (ediff-set-meta-overlay pt (point) elt)) + (progn + (ediff-with-current-buffer elt + (setq bufAname (if (ediff-buffer-live-p ediff-buffer-A) + (buffer-name ediff-buffer-A) + "!!!killed buffer!!!") + bufBname (if (ediff-buffer-live-p ediff-buffer-B) + (buffer-name ediff-buffer-B) + "!!!killed buffer!!!") + bufCname (cond ((not (ediff-3way-job)) + "") + ((ediff-buffer-live-p ediff-buffer-C) + (buffer-name ediff-buffer-C)) + (t "!!!killed buffer!!!"))) + (setq total-diffs (format "%-4d" ediff-number-of-differences) + cur-diff + (cond ((= ediff-current-difference -1) " _") + ((= ediff-current-difference + ediff-number-of-differences) + " $") + (t (format + "%4d" (1+ ediff-current-difference)))) + job-name ediff-job-name)) + ;; back in the meta buf + (setq pt (point)) + (insert cur-diff "/" total-diffs "\t" + (buffer-name elt) + (format ": %s" (ediff-abbrev-jobname job-name))) + (insert + "\n\t\t " bufAname " " bufBname " " bufCname "\n") + (ediff-set-meta-overlay pt (point) elt)))) + ) ; while + (set-buffer-modified-p nil) + (goto-char point) + ))) + +;; Sets overlay around a meta record with 'ediff-meta-info property PROP +;; If optional SESSION-NUMBER, make it a property of the overlay, +;; ediff-meta-session-number +;; PROP is either the ctl or meta buffer (used when we work with the registry) +;; or a session meta descriptor of the form +;; (SESSION-CTL-BUFFER STATUS OBJA OBJB OBJC) +(defun ediff-set-meta-overlay (b e prop &optional session-number hidden) + (let (overl) + (setq overl (ediff-make-overlay b e)) + (if ediff-emacs-p + (ediff-overlay-put overl 'mouse-face 'highlight) + (ediff-overlay-put overl 'highlight t)) + (ediff-overlay-put overl 'ediff-meta-info prop) + (ediff-overlay-put overl 'invisible hidden) + (ediff-overlay-put overl 'follow-link t) + (if (numberp session-number) + (ediff-overlay-put overl 'ediff-meta-session-number session-number)))) + +(defun ediff-mark-for-hiding-at-pos (unmark) + "Mark session for hiding. With prefix arg, unmark." + (interactive "P") + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + ;; ediff-get-meta-info gives error if meta-buf or pos are invalid + (info (ediff-get-meta-info meta-buf pos)) + (session-number (ediff-get-session-number-at-pos pos))) + (ediff-mark-session-for-hiding info unmark) + (ediff-next-meta-item 1) + (save-excursion + (ediff-update-meta-buffer meta-buf nil session-number)) + )) + +;; Returns whether session was marked or unmarked +(defun ediff-mark-session-for-hiding (info unmark) + (let ((session-buf (ediff-get-session-buffer info)) + ignore) + (cond ((eq unmark 'mark) (setq unmark nil)) + ((eq (ediff-get-session-status info) ?H) (setq unmark t)) + (unmark ; says unmark, but the marker is different from H + (setq ignore t))) + (cond (ignore) + (unmark (ediff-set-session-status info nil)) +;;; (if (ediff-buffer-live-p session-buf) +;;; (error "Can't hide active session, %s" (buffer-name session-buf))) + (t (ediff-set-session-status info ?H)))) + unmark) + + +(defun ediff-mark-for-operation-at-pos (unmark) + "Mark session for a group operation. With prefix arg, unmark." + (interactive "P") + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + ;; ediff-get-meta-info gives error if meta-buf or pos are invalid + (info (ediff-get-meta-info meta-buf pos)) + (session-number (ediff-get-session-number-at-pos pos))) + (ediff-mark-session-for-operation info unmark) + (ediff-next-meta-item 1) + (save-excursion + (ediff-update-meta-buffer meta-buf nil session-number)) + )) + + +;; returns whether session was unmarked. +;; remember: this is a toggle op +(defun ediff-mark-session-for-operation (info unmark) + (let (ignore) + (cond ((eq unmark 'mark) (setq unmark nil)) + ((eq (ediff-get-session-status info) ?*) (setq unmark t)) + (unmark ; says unmark, but the marker is different from * + (setq ignore t))) + (cond (ignore) + (unmark (ediff-set-session-status info nil)) + (t (ediff-set-session-status info ?*)))) + unmark) + + +(defun ediff-hide-marked-sessions (unhide) + "Hide marked sessions. With prefix arg, unhide." + (interactive "P") + (let ((grp-buf (ediff-get-group-buffer ediff-meta-list)) + (meta-list (cdr ediff-meta-list)) + (from (if unhide ?I ?H)) + (to (if unhide ?H ?I)) + (numMarked 0) + active-sessions-exist session-buf elt) + (while meta-list + (setq elt (car meta-list) + meta-list (cdr meta-list) + session-buf (ediff-get-session-buffer elt)) + + (if (eq (ediff-get-session-status elt) from) + (progn + (setq numMarked (1+ numMarked)) + (if (and (eq to ?I) (buffer-live-p session-buf)) + ;; shouldn't hide active sessions + (setq active-sessions-exist t) + (ediff-set-session-status elt to))))) + (if (> numMarked 0) + (ediff-update-meta-buffer grp-buf 'must-redraw) + (beep) + (if unhide + (message "Nothing to reveal...") + (message "Nothing to hide..."))) + (if active-sessions-exist + (message "Note: Ediff didn't hide active sessions!")) + )) + +;; Apply OPERATION to marked sessions. Operation expects one argument of type +;; meta-list member (not the first one), i.e., a regular session description. +;; Returns number of marked sessions on which operation was performed +(defun ediff-operate-on-marked-sessions (operation) + (let ((grp-buf (ediff-get-group-buffer ediff-meta-list)) + (meta-list (cdr ediff-meta-list)) + (marksym ?*) + (numMarked 0) + (sessionNum 0) + (diff-buffer ediff-meta-diff-buffer) + session-buf elt) + (while meta-list + (setq elt (car meta-list) + meta-list (cdr meta-list) + sessionNum (1+ sessionNum)) + (cond ((eq (ediff-get-session-status elt) marksym) + (save-excursion + (setq numMarked (1+ numMarked)) + (funcall operation elt sessionNum))) + ;; The following goes into a session represented by a subdirectory + ;; and applies operation to marked sessions there + ((and (ediff-meta-session-p elt) + (ediff-buffer-live-p + (setq session-buf (ediff-get-session-buffer elt)))) + (setq numMarked + (+ numMarked + (ediff-with-current-buffer session-buf + ;; pass meta-diff along + (setq ediff-meta-diff-buffer diff-buffer) + ;; collect diffs in child group + (ediff-operate-on-marked-sessions operation))))))) + (ediff-update-meta-buffer grp-buf 'must-redraw) ; just in case + numMarked + )) + +(defun ediff-append-custom-diff (session sessionNum) + (or (ediff-collect-diffs-metajob) + (error "Can't compute multifile patch in this context")) + (let ((session-buf (ediff-get-session-buffer session)) + (meta-diff-buff ediff-meta-diff-buffer) + (metajob ediff-metajob-name) + tmp-buf custom-diff-buf) + (if (ediff-buffer-live-p session-buf) + (ediff-with-current-buffer session-buf + (if (eq ediff-control-buffer session-buf) ; individual session + (progn + (ediff-compute-custom-diffs-maybe) + (setq custom-diff-buf ediff-custom-diff-buffer))))) + + (or (ediff-buffer-live-p meta-diff-buff) + (error "Ediff: something wrong--killed multiple diff's buffer")) + + (cond ((ediff-buffer-live-p custom-diff-buf) + ;; for live session buffers we do them first because the user may + ;; have changed them with respect to the underlying files + (save-excursion + (set-buffer meta-diff-buff) + (goto-char (point-max)) + (insert-buffer-substring custom-diff-buf) + (insert "\n"))) + ;; if ediff session is not live, run diff directly on the files + ((memq metajob '(ediff-directories + ediff-merge-directories + ediff-merge-directories-with-ancestor)) + ;; get diffs by calling shell command on ediff-custom-diff-program + (save-excursion + (set-buffer (setq tmp-buf (get-buffer-create ediff-tmp-buffer))) + (erase-buffer) + (shell-command + (format "%s %s %s %s" + ediff-custom-diff-program ediff-custom-diff-options + (ediff-get-session-objA-name session) + (ediff-get-session-objB-name session)) + t)) + (save-excursion + (set-buffer meta-diff-buff) + (goto-char (point-max)) + (insert-buffer-substring tmp-buf) + (insert "\n"))) + (t + (ediff-kill-buffer-carefully meta-diff-buff) + (error "Session %d compares versions of file. Such session must be active to enable multifile patch collection" sessionNum ))) + )) + +(defun ediff-collect-custom-diffs () + "Collect custom diffs of marked sessions in buffer `*Ediff Multifile Diffs*'. +This operation is defined only for `ediff-directories' and +`ediff-directory-revisions', since its intent is to produce +multifile patches. For `ediff-directory-revisions', we insist that +all marked sessions must be active." + (interactive) + (or (ediff-buffer-live-p ediff-meta-diff-buffer) + (setq ediff-meta-diff-buffer + (get-buffer-create + (ediff-unique-buffer-name "*Ediff Multifile Diffs" "*")))) + (ediff-with-current-buffer ediff-meta-diff-buffer + (setq buffer-read-only nil) + (erase-buffer)) + (if (> (ediff-operate-on-marked-sessions 'ediff-append-custom-diff) 0) + ;; did something + (progn + (display-buffer ediff-meta-diff-buffer 'not-this-window) + (ediff-with-current-buffer ediff-meta-diff-buffer + (set-buffer-modified-p nil) + (setq buffer-read-only t))) + (beep) + (message "No marked sessions found"))) + +(defun ediff-meta-show-patch () + "Show the multi-file patch associated with this group session." + (interactive) + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + (info (ediff-get-meta-info meta-buf pos 'noerror)) + (patchbuffer ediff-meta-patchbufer)) + (if (ediff-buffer-live-p patchbuffer) + (ediff-with-current-buffer patchbuffer + (save-restriction + (if (not info) + (widen) + (narrow-to-region + (ediff-get-session-objB-name info) + (ediff-get-session-objC-name info))) + (set-buffer (get-buffer-create ediff-tmp-buffer)) + (erase-buffer) + (insert-buffer-substring patchbuffer) + (goto-char (point-min)) + (display-buffer ediff-tmp-buffer 'not-this-window) + )) + (error "The patch buffer wasn't found")))) + + +;; This function executes in meta buffer. It knows where event happened. +(defun ediff-filegroup-action () + "Execute appropriate action for a selected session." + (interactive) + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + ;; ediff-get-meta-info gives error if meta-buf or pos are invalid + (info (ediff-get-meta-info meta-buf pos)) + (session-buf (ediff-get-session-buffer info)) + (session-number (ediff-get-session-number-at-pos pos meta-buf)) + (default-regexp (eval ediff-default-filtering-regexp)) + merge-autostore-dir file1 file2 file3 regexp) + + (setq file1 (ediff-get-session-objA-name info) + file2 (ediff-get-session-objB-name info) + file3 (ediff-get-session-objC-name info)) + + ;; make sure we don't start on hidden sessions + ;; ?H means marked for hiding. ?I means invalid (hidden). + (if (memq (ediff-get-session-status info) '(?I)) + (progn + (beep) + (if (y-or-n-p "This session is marked as hidden, unmark? ") + (progn + (ediff-set-session-status info nil) + (ediff-update-meta-buffer meta-buf nil session-number)) + (error "Aborted")))) + + (ediff-with-current-buffer meta-buf + (setq merge-autostore-dir + (ediff-get-group-merge-autostore-dir ediff-meta-list)) + (goto-char pos) ; if the user clicked on session--move point there + ;; First handle sessions involving directories (which are themselves + ;; session groups) + ;; After that handle individual sessions + (cond ((ediff-meta-session-p info) + ;; do ediff/ediff-merge on subdirectories + (if (ediff-buffer-live-p session-buf) + (ediff-show-meta-buffer session-buf) + (setq regexp + (read-string + (if (stringp default-regexp) + (format + "Filter through regular expression (default %s): " + default-regexp) + "Filter through regular expression: ") + nil + 'ediff-filtering-regexp-history + (eval ediff-default-filtering-regexp))) + (ediff-directories-internal + file1 file2 file3 regexp + ediff-session-action-function + ediff-metajob-name + ;; make it update (car info) after startup + `(list (lambda () + ;; child session group should know its parent + (setq ediff-parent-meta-buffer + (quote ,ediff-meta-buffer) + ediff-meta-session-number + ,session-number) + ;; and parent will know its child + (setcar (quote ,info) ediff-meta-buffer)))))) + + ;; Do ediff-revision on a subdirectory + ((and (ediff-one-filegroup-metajob) + (ediff-revision-metajob) + (file-directory-p file1)) + (if (ediff-buffer-live-p session-buf) + (ediff-show-meta-buffer session-buf) + (setq regexp (read-string "Filter through regular expression: " + nil 'ediff-filtering-regexp-history)) + (ediff-directory-revisions-internal + file1 regexp + ediff-session-action-function ediff-metajob-name + ;; make it update (car info) after startup + `(list (lambda () + ;; child session group should know its parent and + ;; its number + (setq ediff-parent-meta-buffer + (quote ,ediff-meta-buffer) + ediff-meta-session-number + ,session-number) + ;; and parent will know its child + (setcar (quote ,info) ediff-meta-buffer)))))) + + ;; From here on---only individual session handlers + + ;; handle an individual session with a live control buffer + ((ediff-buffer-live-p session-buf) + (ediff-with-current-buffer session-buf + (setq ediff-mouse-pixel-position (mouse-pixel-position)) + (ediff-recenter 'no-rehighlight))) + + ((ediff-problematic-session-p info) + (beep) + (if (y-or-n-p + "This session has no ancestor. Merge without the ancestor? ") + (ediff-merge-files + file1 file2 + ;; provide startup hooks + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) ,session-number))) + nil 'local) + (setq ediff-meta-buffer ,(current-buffer) + ediff-meta-session-number + ,session-number) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1)) + )) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below + (setcar + (quote ,info) ediff-control-buffer)))) + (error "Aborted"))) + ((ediff-one-filegroup-metajob) ; needs 1 file arg + (funcall ediff-session-action-function + file1 + ;; provide startup hooks + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-meta-buffer ,(current-buffer) + ediff-meta-session-number + ,session-number) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below + (setcar + (quote ,info) ediff-control-buffer))))) + ((not (ediff-metajob3)) ; need 2 file args + (funcall ediff-session-action-function + file1 file2 + ;; provide startup hooks + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-meta-buffer ,(current-buffer) + ediff-meta-session-number + ,session-number) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below + (setcar + (quote ,info) ediff-control-buffer))))) + ((ediff-metajob3) ; need 3 file args + (funcall ediff-session-action-function + file1 file2 file3 + ;; arrange startup hooks + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + (setq ediff-meta-buffer , (current-buffer) + ediff-meta-session-number + ,session-number) + ;; this arranges that ediff-startup will pass + ;; the value of ediff-control-buffer back to + ;; the meta level, to the record in the meta + ;; list containing the information about the + ;; session associated with that + ;; ediff-control-buffer + (setcar + (quote ,info) ediff-control-buffer))))) + ) ; cond + ) ; eval in meta-buf + )) + +(defun ediff-registry-action () + "Switch to a selected session." + (interactive) + (let* ((pos (ediff-event-point last-command-event)) + (buf (ediff-event-buffer last-command-event)) + (ctl-buf (ediff-get-meta-info buf pos))) + + (if (ediff-buffer-live-p ctl-buf) + ;; check if this is ediff-control-buffer or ediff-meta-buffer + (if (ediff-with-current-buffer ctl-buf + (eq (key-binding "q") 'ediff-quit-meta-buffer)) + ;; it's a meta-buffer -- last action should just display it + (ediff-show-meta-buffer ctl-buf t) + ;; it's a session buffer -- invoke go back to session + (ediff-with-current-buffer ctl-buf + (setq ediff-mouse-pixel-position (mouse-pixel-position)) + (ediff-recenter 'no-rehighlight))) + (beep) + (message "You've selected a stale session --- try again") + (ediff-update-registry)) + (ediff-with-current-buffer buf + (goto-char pos)) + )) + + +;; If session number is t, means don't update meta buffer +(defun ediff-show-meta-buffer (&optional meta-buf session-number) + "Show the session group buffer." + (interactive) + (run-hooks 'ediff-before-directory-setup-hooks) + (let (wind frame silent) + (if meta-buf (setq silent t)) + + (setq meta-buf (or meta-buf ediff-meta-buffer)) + (cond ((not (bufferp meta-buf)) + (error "This Ediff session is not part of a session group")) + ((not (ediff-buffer-live-p meta-buf)) + (error + "Can't find this session's group panel -- session itself is ok"))) + + (cond ((numberp session-number) + (ediff-update-meta-buffer meta-buf nil session-number)) + ;; if session-number is t, don't update + (session-number) + (t (ediff-cleanup-meta-buffer meta-buf))) + + (ediff-with-current-buffer meta-buf + (save-excursion + (cond ((setq wind (ediff-get-visible-buffer-window meta-buf)) + (or silent + (message + "Already showing the group panel for this session")) + (set-window-buffer wind meta-buf) + (select-window wind)) + ((window-live-p (setq wind ediff-window-C)) ;in merge--merge buf + (set-window-buffer ediff-window-C meta-buf) + (select-window wind)) + ((window-live-p (setq wind ediff-window-A)) + (set-window-buffer ediff-window-A meta-buf) + (select-window wind)) + ((window-live-p (setq wind ediff-window-B)) + (set-window-buffer ediff-window-B meta-buf) + (select-window wind)) + ((and + (setq wind + (ediff-get-visible-buffer-window ediff-registry-buffer)) + (ediff-window-display-p)) + (select-window wind) + (other-window 1) + (set-window-buffer (selected-window) meta-buf)) + (t (ediff-skip-unsuitable-frames 'ok-unsplittable) + (set-window-buffer (selected-window) meta-buf))) + )) + (if (and (ediff-window-display-p) + (window-live-p + (setq wind (ediff-get-visible-buffer-window meta-buf)))) + (progn + (setq frame (window-frame wind)) + (raise-frame frame) + (ediff-reset-mouse frame))) + (sit-for 0) ; sometimes needed to synch the display and ensure that the + ; point ends up after the just completed session + (run-hooks 'ediff-show-session-group-hook) + )) + +(defun ediff-show-current-session-meta-buffer () + (interactive) + (ediff-show-meta-buffer nil ediff-meta-session-number)) + +(defun ediff-show-meta-buff-from-registry () + "Display the session group buffer for a selected session group." + (interactive) + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + (info (ediff-get-meta-info meta-buf pos)) + (meta-or-session-buf info)) + (ediff-with-current-buffer meta-or-session-buf + (ediff-show-meta-buffer nil t)))) + +;;;###autoload +(defun ediff-show-registry () + "Display Ediff's registry." + (interactive) + (ediff-update-registry) + (if (not (ediff-buffer-live-p ediff-registry-buffer)) + (error "No active Ediff sessions or corrupted session registry")) + (let (wind frame) + ;; for some reason, point moves in ediff-registry-buffer, so we preserve it + ;; explicitly + (ediff-with-current-buffer ediff-registry-buffer + (save-excursion + (cond ((setq wind + (ediff-get-visible-buffer-window ediff-registry-buffer)) + (message "Already showing the registry") + (set-window-buffer wind ediff-registry-buffer) + (select-window wind)) + ((window-live-p ediff-window-C) + (set-window-buffer ediff-window-C ediff-registry-buffer) + (select-window ediff-window-C)) + ((window-live-p ediff-window-A) + (set-window-buffer ediff-window-A ediff-registry-buffer) + (select-window ediff-window-A)) + ((window-live-p ediff-window-B) + (set-window-buffer ediff-window-B ediff-registry-buffer) + (select-window ediff-window-B)) + ((and (setq wind + (ediff-get-visible-buffer-window ediff-meta-buffer)) + (ediff-window-display-p)) + (select-window wind) + (other-window 1) + (set-window-buffer (selected-window) ediff-registry-buffer)) + (t (ediff-skip-unsuitable-frames 'ok-unsplittable) + (set-window-buffer (selected-window) ediff-registry-buffer))) + )) + (if (ediff-window-display-p) + (progn + (setq frame + (window-frame + (ediff-get-visible-buffer-window ediff-registry-buffer))) + (raise-frame frame) + (ediff-reset-mouse frame))) + (run-hooks 'ediff-show-registry-hook) + )) + +;;;###autoload +(defalias 'eregistry 'ediff-show-registry) + +;; If meta-buf doesn't exist, it is created. In that case, id doesn't have a +;; parent meta-buf +;; Check if META-BUF exists before calling this function +;; Optional MUST-REDRAW, if non-nil, would force redrawal of the whole meta +;; buffer. Otherwise, it will just go over the buffer and update activity marks +;; and session status. +;; SESSION-NUMBER, if specified, says which session caused the update. +(defun ediff-update-meta-buffer (meta-buf &optional must-redraw session-number) + (if (ediff-buffer-live-p meta-buf) + (ediff-with-current-buffer meta-buf + (let (overl) + (cond (must-redraw ; completely redraw the meta buffer + (funcall ediff-meta-redraw-function ediff-meta-list)) + ((numberp session-number) ; redraw only for the given session + (ediff-update-session-marker-in-dir-meta-buffer + session-number)) + (t ; update what changed only, but scan the entire meta buffer + (ediff-update-markers-in-dir-meta-buffer ediff-meta-list))) + (setq overl (ediff-get-meta-overlay-at-pos (point))) + ;; skip the invisible sessions + (while (and overl (ediff-overlay-get overl 'invisible)) + (ediff-next-meta-item1) + (setq overl (ediff-get-meta-overlay-at-pos (point)))) + )))) + +(defun ediff-update-registry () + (ediff-with-current-buffer (current-buffer) + (if (ediff-buffer-live-p ediff-registry-buffer) + (ediff-redraw-registry-buffer) + (ediff-prepare-meta-buffer + 'ediff-registry-action + ediff-session-registry + "*Ediff Registry" + 'ediff-redraw-registry-buffer + 'ediff-registry)) + )) + +;; If meta-buf exists, it is redrawn along with parent. +;; Otherwise, nothing happens. +(defun ediff-cleanup-meta-buffer (meta-buffer) + (if (ediff-buffer-live-p meta-buffer) + (ediff-with-current-buffer meta-buffer + (ediff-update-meta-buffer meta-buffer) + (if (ediff-buffer-live-p ediff-parent-meta-buffer) + (ediff-update-meta-buffer + ediff-parent-meta-buffer nil ediff-meta-session-number))))) + +;; t if no session is in progress +(defun ediff-safe-to-quit (meta-buffer) + (if (ediff-buffer-live-p meta-buffer) + (let ((lis ediff-meta-list) + (cont t) + buffer-read-only) + ;;(ediff-update-meta-buffer meta-buffer) + (ediff-with-current-buffer meta-buffer + (setq lis (cdr lis)) ; discard the description part of meta-list + (while (and cont lis) + (if (ediff-buffer-live-p + (ediff-get-group-buffer lis)) ; in progress + (setq cont nil)) + (setq lis (cdr lis))) + cont)))) + +(defun ediff-quit-meta-buffer () + "If the group has no active session, delete the meta buffer. +If no session is in progress, ask to confirm before deleting meta buffer. +Otherwise, bury the meta buffer. +If this is a session registry buffer then just bury it." + (interactive) + (let* ((buf (current-buffer)) + (dir-diffs-buffer ediff-dir-diffs-buffer) + (meta-diff-buffer ediff-meta-diff-buffer) + (session-number ediff-meta-session-number) + (parent-buf ediff-parent-meta-buffer) + (dont-show-registry (eq buf ediff-registry-buffer))) + (if dont-show-registry + (bury-buffer) + ;;(ediff-cleanup-meta-buffer buf) + (cond ((and (ediff-safe-to-quit buf) + (y-or-n-p "Quit this session group? ")) + (run-hooks 'ediff-quit-session-group-hook) + (message "") + (ediff-dispose-of-meta-buffer buf)) + ((ediff-safe-to-quit buf) + (bury-buffer)) + (t + (error + "This session group has active sessions---cannot exit"))) + (ediff-update-meta-buffer parent-buf nil session-number) + (ediff-kill-buffer-carefully dir-diffs-buffer) + (ediff-kill-buffer-carefully meta-diff-buffer) + (if (ediff-buffer-live-p parent-buf) + (progn + (setq dont-show-registry t) + (ediff-show-meta-buffer parent-buf session-number))) + ) + (or dont-show-registry + (ediff-show-registry)))) + +(defun ediff-dispose-of-meta-buffer (buf) + (setq ediff-session-registry (delq buf ediff-session-registry)) + (ediff-with-current-buffer buf + (if (ediff-buffer-live-p ediff-dir-diffs-buffer) + (kill-buffer ediff-dir-diffs-buffer))) + (kill-buffer buf)) + + +;; Obtain information on a meta record where the user clicked or typed +;; BUF is the buffer where this happened and POINT is the position +;; If optional NOERROR arg is given, don't report error and return nil if no +;; meta info is found on line. +(defun ediff-get-meta-info (buf point &optional noerror) + (let (result olist tmp) + (if (and point (ediff-buffer-live-p buf)) + (ediff-with-current-buffer buf + (ediff-cond-compile-for-xemacs-or-emacs + (setq result ; xemacs + (if (setq tmp (extent-at point buf 'ediff-meta-info)) + (ediff-overlay-get tmp 'ediff-meta-info))) + (progn ; emacs + (setq olist (overlays-at point)) + (setq olist + (mapcar (lambda (elt) + (unless (overlay-get elt 'invisible) + (overlay-get elt 'ediff-meta-info))) + olist)) + (while (and olist (null (car olist))) + (setq olist (cdr olist))) + (setq result (car olist))) + ) + )) + (if result + result + (if noerror + nil + (ediff-update-registry) + (error "No session info in this line"))))) + + +(defun ediff-get-meta-overlay-at-pos (point) + (ediff-cond-compile-for-xemacs-or-emacs + (extent-at point (current-buffer) 'ediff-meta-info) ; xemacs + ;; emacs + (let* ((overl-list (overlays-at point)) + (overl (car overl-list))) + (while (and overl (null (overlay-get overl 'ediff-meta-info))) + (setq overl-list (cdr overl-list) + overl (car overl-list))) + overl) + ) + ) + +(defsubst ediff-get-session-number-at-pos (point &optional meta-buffer) + (setq meta-buffer (if (ediff-buffer-live-p meta-buffer) + meta-buffer + (current-buffer))) + (ediff-with-current-buffer meta-buffer + (ediff-overlay-get + (ediff-get-meta-overlay-at-pos point) 'ediff-meta-session-number))) + + +;; Return location of the next meta overlay after point +(defun ediff-next-meta-overlay-start (point) + (if (eobp) + (goto-char (point-min)) + (let ((overl (ediff-get-meta-overlay-at-pos point))) + (ediff-cond-compile-for-xemacs-or-emacs + (progn ; xemacs + (if overl + (setq overl (next-extent overl)) + (setq overl (next-extent (current-buffer)))) + (if overl + (extent-start-position overl) + (point-max))) + ;; emacs + (if overl + ;; note: end of current overlay is the beginning of the next one + (overlay-end overl) + (next-overlay-change point)) + ) + ) + )) + + +(defun ediff-previous-meta-overlay-start (point) + (if (bobp) + (goto-char (point-max)) + (let ((overl (ediff-get-meta-overlay-at-pos point))) + (ediff-cond-compile-for-xemacs-or-emacs + (progn + (if overl + (setq overl (previous-extent overl)) + (setq overl (previous-extent (current-buffer)))) + (if overl + (extent-start-position overl) + (point-min))) + (progn + (if overl (setq point (overlay-start overl))) + ;; to get to the beginning of prev overlay + (if (not (bobp)) + ;; trick to overcome an emacs bug--doesn't always find previous + ;; overlay change correctly + (setq point (1- point))) + (setq point (previous-overlay-change point)) + ;; If we are not over an overlay after subtracting 1, it means we are + ;; in the description area preceding session records. In this case, + ;; goto the top of the registry buffer. + (or (car (overlays-at point)) + (setq point (point-min))) + point) + ) + ))) + +;; this is the action invoked when the user selects a patch from the meta +;; buffer. +(defun ediff-patch-file-form-meta (file &optional startup-hooks) + (let* ((pos (ediff-event-point last-command-event)) + (meta-buf (ediff-event-buffer last-command-event)) + ;; ediff-get-meta-info gives error if meta-buf or pos are invalid + (info (ediff-get-meta-info meta-buf pos)) + (meta-patchbuf ediff-meta-patchbufer) + session-buf beg-marker end-marker) + + (if (or (file-directory-p file) (string-match "/dev/null" file)) + (error "`%s' is not an ordinary file" (file-name-as-directory file))) + (setq session-buf (ediff-get-session-buffer info) + beg-marker (ediff-get-session-objB-name info) + end-marker (ediff-get-session-objC-name info)) + + (or (ediff-buffer-live-p session-buf) ; either an active patch session + (null session-buf) ; or it is a virgin session + (error + "Patch has already been applied to this file -- can't repeat!")) + + (ediff-with-current-buffer meta-patchbuf + (save-restriction + (widen) + (narrow-to-region beg-marker end-marker) + (ediff-patch-file-internal meta-patchbuf file startup-hooks))))) + + +(defun ediff-unmark-all-for-operation () + "Unmark all sessions marked for operation." + (interactive) + (let ((list (cdr ediff-meta-list)) + elt) + (while (setq elt (car list)) + (ediff-mark-session-for-operation elt 'unmark) + (setq list (cdr list)))) + (ediff-update-meta-buffer (current-buffer) 'must-redraw)) + +(defun ediff-unmark-all-for-hiding () + "Unmark all sessions marked for hiding." + (interactive) + (let ((list (cdr ediff-meta-list)) + elt) + (while (setq elt (car list)) + (ediff-mark-session-for-hiding elt 'unmark) + (setq list (cdr list)))) + (ediff-update-meta-buffer (current-buffer) 'must-redraw)) + + +;; ACTION is ?h, ?m, ?=: to mark for hiding, mark for operation, or simply +;; indicate which are equal files +(defun ediff-meta-mark-equal-files (&optional action) + "Run through the session list and mark identical files. +This is used only for sessions that involve 2 or 3 files at the same time. +ACTION is an optional argument that can be ?h, ?m, ?=, to mark for hiding, mark +for operation, or simply indicate which are equal files. If it is nil, then +`last-command-char' is used to decide which action to take." + (interactive) + (if (null action) + (setq action last-command-char)) + (let ((list (cdr ediff-meta-list)) + marked1 marked2 marked3 + fileinfo1 fileinfo2 fileinfo3 elt) + (message "Comparing files ...") + (while (setq elt (car list)) + (setq fileinfo1 (ediff-get-session-objA elt) + fileinfo2 (ediff-get-session-objB elt) + fileinfo3 (ediff-get-session-objC elt)) + (ediff-set-file-eqstatus fileinfo1 nil) + (ediff-set-file-eqstatus fileinfo2 nil) + (ediff-set-file-eqstatus fileinfo3 nil) + + (setq marked1 t + marked2 t + marked3 t) + (or (ediff-mark-if-equal fileinfo1 fileinfo2) + (setq marked1 nil)) + (if (ediff-metajob3) + (progn + (or (ediff-mark-if-equal fileinfo1 fileinfo3) + (setq marked2 nil)) + (or (ediff-mark-if-equal fileinfo2 fileinfo3) + (setq marked3 nil)))) + (if (and marked1 marked2 marked3) + (cond ((eq action ?h) + (ediff-mark-session-for-hiding elt 'mark)) + ((eq action ?m) + (ediff-mark-session-for-operation elt 'mark)) + )) + (setq list (cdr list))) + (message "Comparing files ... Done")) + (setq ediff-recurse-to-subdirectories nil) + (ediff-update-meta-buffer (current-buffer) 'must-redraw)) + +;; mark files 1 and 2 as equal, if they are. +;; returns t, if something was marked +(defun ediff-mark-if-equal (fileinfo1 fileinfo2) + (let ((f1 (car fileinfo1)) + (f2 (car fileinfo2))) + (if (and (stringp f1) (stringp f2) (ediff-same-contents f1 f2)) + (progn + (ediff-set-file-eqstatus fileinfo1 t) + (ediff-set-file-eqstatus fileinfo2 t) + )) + )) + + +(provide 'ediff-mult) + + +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) +;;; End: + +;;; arch-tag: c8a76898-f96f-4d9c-be9d-129134017188 +;;; ediff-mult.el ends here diff --git a/xemacs-packages/lisp/ediff/ediff-mult.elc b/xemacs-packages/lisp/ediff/ediff-mult.elc new file mode 100644 index 0000000000000000000000000000000000000000..f35e39577b5c633e738f95f7a703eb316d2114ee GIT binary patch literal 50192 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